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/webrender/RenderThread.h"
15 #include "mozilla/webrender/WebRenderAPI.h"
16 #include "mozilla/webrender/webrender_ffi.h"
17 #include "mozilla/gfx/BuildConstants.h"
18 #include "mozilla/gfx/gfxConfigManager.h"
19 #include "mozilla/gfx/gfxVars.h"
20 #include "mozilla/gfx/GPUProcessManager.h"
21 #include "mozilla/gfx/GraphicsMessages.h"
22 #include "mozilla/gfx/CanvasManagerChild.h"
23 #include "mozilla/gfx/CanvasManagerParent.h"
24 #include "mozilla/ClearOnShutdown.h"
25 #include "mozilla/StaticPrefs_accessibility.h"
26 #include "mozilla/StaticPrefs_apz.h"
27 #include "mozilla/StaticPrefs_canvas.h"
28 #include "mozilla/StaticPrefs_gfx.h"
29 #include "mozilla/StaticPrefs_layout.h"
30 #include "mozilla/StaticPrefs_layers.h"
31 #include "mozilla/StaticPrefs_media.h"
32 #include "mozilla/StaticPrefs_webgl.h"
33 #include "mozilla/StaticPrefs_widget.h"
34 #include "mozilla/Telemetry.h"
35 #include "mozilla/TimeStamp.h"
36 #include "mozilla/Unused.h"
37 #include "mozilla/IntegerPrintfMacros.h"
38 #include "mozilla/Base64.h"
39 
40 #include "mozilla/Logging.h"
41 #include "mozilla/Components.h"
42 #include "nsAppRunner.h"
43 #include "nsAppDirectoryServiceDefs.h"
44 #include "nsCSSProps.h"
45 
46 #include "gfxCrashReporterUtils.h"
47 #include "gfxPlatform.h"
48 
49 #include "gfxBlur.h"
50 #include "gfxEnv.h"
51 #include "gfxTextRun.h"
52 #include "gfxUserFontSet.h"
53 #include "gfxConfig.h"
54 #include "GfxDriverInfo.h"
55 #include "VRProcessManager.h"
56 #include "VRThread.h"
57 
58 #ifdef XP_WIN
59 #  include <process.h>
60 #  define getpid _getpid
61 #else
62 #  include <unistd.h>
63 #endif
64 
65 #include "nsXULAppAPI.h"
66 #include "nsIXULAppInfo.h"
67 #include "nsDirectoryServiceUtils.h"
68 #include "nsDirectoryServiceDefs.h"
69 
70 #if defined(XP_WIN)
71 #  include "gfxWindowsPlatform.h"
72 #  include "mozilla/widget/WinWindowOcclusionTracker.h"
73 #elif defined(XP_MACOSX)
74 #  include "gfxPlatformMac.h"
75 #  include "gfxQuartzSurface.h"
76 #  include "nsCocoaFeatures.h"
77 #elif defined(MOZ_WIDGET_GTK)
78 #  include "gfxPlatformGtk.h"
79 #elif defined(ANDROID)
80 #  include "gfxAndroidPlatform.h"
81 #endif
82 #if defined(MOZ_WIDGET_ANDROID)
83 #  include "mozilla/jni/Utils.h"  // for IsFennec
84 #endif
85 
86 #ifdef XP_WIN
87 #  include "mozilla/WindowsVersion.h"
88 #  include "WinUtils.h"
89 #endif
90 
91 #include "nsGkAtoms.h"
92 #include "gfxPlatformFontList.h"
93 #include "gfxContext.h"
94 #include "gfxImageSurface.h"
95 #include "nsUnicodeProperties.h"
96 #include "harfbuzz/hb.h"
97 #include "gfxGraphiteShaper.h"
98 #include "gfx2DGlue.h"
99 #include "gfxGradientCache.h"
100 #include "gfxUtils.h"  // for NextPowerOfTwo
101 #include "gfxFontMissingGlyphs.h"
102 
103 #include "nsExceptionHandler.h"
104 #include "nsServiceManagerUtils.h"
105 #include "nsTArray.h"
106 #include "nsIObserverService.h"
107 #include "nsIScreenManager.h"
108 #include "MainThreadUtils.h"
109 
110 #include "nsWeakReference.h"
111 
112 #include "cairo.h"
113 #include "qcms.h"
114 
115 #include "imgITools.h"
116 
117 #include "plstr.h"
118 #include "nsCRT.h"
119 #include "GLContext.h"
120 #include "GLContextProvider.h"
121 #include "mozilla/gfx/Logging.h"
122 
123 #ifdef __GNUC__
124 #  pragma GCC diagnostic push
125 #  pragma GCC diagnostic ignored "-Wshadow"
126 #endif
127 #include "skia/include/core/SkGraphics.h"
128 #ifdef MOZ_ENABLE_FREETYPE
129 #  include "skia/include/ports/SkTypeface_cairo.h"
130 #endif
131 #include "mozilla/gfx/SkMemoryReporter.h"
132 #ifdef __GNUC__
133 #  pragma GCC diagnostic pop  // -Wshadow
134 #endif
135 static const uint32_t kDefaultGlyphCacheSize = -1;
136 
137 #include "mozilla/Preferences.h"
138 #include "mozilla/Assertions.h"
139 #include "mozilla/Atomics.h"
140 #include "mozilla/Attributes.h"
141 #include "mozilla/Mutex.h"
142 
143 #include "nsAlgorithm.h"
144 #include "nsIGfxInfo.h"
145 #include "nsIXULRuntime.h"
146 #include "VsyncSource.h"
147 #include "SoftwareVsyncSource.h"
148 #include "nscore.h"  // for NS_FREE_PERMANENT_DATA
149 #include "mozilla/dom/ContentChild.h"
150 #include "mozilla/dom/ContentParent.h"
151 #include "mozilla/dom/TouchEvent.h"
152 #include "gfxVR.h"
153 #include "VRManager.h"
154 #include "VRManagerChild.h"
155 #include "mozilla/gfx/GPUParent.h"
156 #include "prsystem.h"
157 
158 #include "mozilla/gfx/2D.h"
159 #include "mozilla/gfx/SourceSurfaceCairo.h"
160 
161 using namespace mozilla;
162 using namespace mozilla::layers;
163 using namespace mozilla::gl;
164 using namespace mozilla::gfx;
165 
166 gfxPlatform* gPlatform = nullptr;
167 static bool gEverInitialized = false;
168 
169 static int32_t gLastUsedFrameRate = -1;
170 
171 const ContentDeviceData* gContentDeviceInitData = nullptr;
172 
173 Atomic<bool, MemoryOrdering::ReleaseAcquire> gfxPlatform::gCMSInitialized;
174 CMSMode gfxPlatform::gCMSMode = CMSMode::Off;
175 
176 // These two may point to the same profile
177 qcms_profile* gfxPlatform::gCMSOutputProfile = nullptr;
178 qcms_profile* gfxPlatform::gCMSsRGBProfile = nullptr;
179 
180 qcms_transform* gfxPlatform::gCMSRGBTransform = nullptr;
181 qcms_transform* gfxPlatform::gCMSInverseRGBTransform = nullptr;
182 qcms_transform* gfxPlatform::gCMSRGBATransform = nullptr;
183 qcms_transform* gfxPlatform::gCMSBGRATransform = nullptr;
184 
185 /// This override of the LogForwarder, initially used for the critical graphics
186 /// errors, is sending the log to the crash annotations as well, but only
187 /// if the capacity set with the method below is >= 2.  We always retain the
188 /// very first critical message, and the latest capacity-1 messages are
189 /// rotated through. Note that we don't expect the total number of times
190 /// this gets called to be large - it is meant for critical errors only.
191 
192 class CrashStatsLogForwarder : public mozilla::gfx::LogForwarder {
193  public:
194   explicit CrashStatsLogForwarder(CrashReporter::Annotation aKey);
195   void Log(const std::string& aString) override;
196   void CrashAction(LogReason aReason) override;
197   bool UpdateStringsVector(const std::string& aString) override;
198 
199   LoggingRecord LoggingRecordCopy() override;
200 
201   void SetCircularBufferSize(uint32_t aCapacity);
202 
203  private:
204   // Helper for the Log()
205   void UpdateCrashReport();
206 
207  private:
208   LoggingRecord mBuffer;
209   CrashReporter::Annotation mCrashCriticalKey;
210   uint32_t mMaxCapacity;
211   int32_t mIndex;
212   Mutex mMutex;
213 };
214 
CrashStatsLogForwarder(CrashReporter::Annotation aKey)215 CrashStatsLogForwarder::CrashStatsLogForwarder(CrashReporter::Annotation aKey)
216     : mBuffer(),
217       mCrashCriticalKey(aKey),
218       mMaxCapacity(0),
219       mIndex(-1),
220       mMutex("CrashStatsLogForwarder") {}
221 
SetCircularBufferSize(uint32_t aCapacity)222 void CrashStatsLogForwarder::SetCircularBufferSize(uint32_t aCapacity) {
223   MutexAutoLock lock(mMutex);
224 
225   mMaxCapacity = aCapacity;
226   mBuffer.reserve(static_cast<size_t>(aCapacity));
227 }
228 
LoggingRecordCopy()229 LoggingRecord CrashStatsLogForwarder::LoggingRecordCopy() {
230   MutexAutoLock lock(mMutex);
231   return mBuffer;
232 }
233 
UpdateStringsVector(const std::string & aString)234 bool CrashStatsLogForwarder::UpdateStringsVector(const std::string& aString) {
235   // We want at least the first one and the last one.  Otherwise, no point.
236   if (mMaxCapacity < 2) {
237     return false;
238   }
239 
240   mIndex += 1;
241   MOZ_ASSERT(mIndex >= 0);
242 
243   // index will count 0, 1, 2, ..., max-1, 1, 2, ..., max-1, 1, 2, ...
244   int32_t index = mIndex ? (mIndex - 1) % (mMaxCapacity - 1) + 1 : 0;
245   MOZ_ASSERT(index >= 0 && index < (int32_t)mMaxCapacity);
246   MOZ_ASSERT(index <= mIndex && index <= (int32_t)mBuffer.size());
247 
248   double tStamp = (TimeStamp::NowLoRes() - TimeStamp::ProcessCreation())
249                       .ToSecondsSigDigits();
250 
251   // Checking for index >= mBuffer.size(), rather than index == mBuffer.size()
252   // just out of paranoia, but we know index <= mBuffer.size().
253   LoggingRecordEntry newEntry(mIndex, aString, tStamp);
254   if (index >= static_cast<int32_t>(mBuffer.size())) {
255     mBuffer.push_back(newEntry);
256   } else {
257     mBuffer[index] = newEntry;
258   }
259   return true;
260 }
261 
UpdateCrashReport()262 void CrashStatsLogForwarder::UpdateCrashReport() {
263   std::stringstream message;
264   std::string logAnnotation;
265 
266   switch (XRE_GetProcessType()) {
267     case GeckoProcessType_Default:
268       logAnnotation = "|[";
269       break;
270     case GeckoProcessType_Content:
271       logAnnotation = "|[C";
272       break;
273     case GeckoProcessType_GPU:
274       logAnnotation = "|[G";
275       break;
276     default:
277       logAnnotation = "|[X";
278       break;
279   }
280 
281   for (auto& it : mBuffer) {
282     message << logAnnotation << Get<0>(it) << "]" << Get<1>(it)
283             << " (t=" << Get<2>(it) << ") ";
284   }
285 
286   nsCString reportString(message.str().c_str());
287   nsresult annotated =
288       CrashReporter::AnnotateCrashReport(mCrashCriticalKey, reportString);
289 
290   if (annotated != NS_OK) {
291     printf("Crash Annotation %s: %s",
292            CrashReporter::AnnotationToString(mCrashCriticalKey),
293            message.str().c_str());
294   }
295 }
296 
297 class LogForwarderEvent : public Runnable {
298   virtual ~LogForwarderEvent() = default;
299 
300  public:
NS_INLINE_DECL_REFCOUNTING_INHERITED(LogForwarderEvent,Runnable)301   NS_INLINE_DECL_REFCOUNTING_INHERITED(LogForwarderEvent, Runnable)
302 
303   explicit LogForwarderEvent(const nsCString& aMessage)
304       : mozilla::Runnable("LogForwarderEvent"), mMessage(aMessage) {}
305 
Run()306   NS_IMETHOD Run() override {
307     MOZ_ASSERT(NS_IsMainThread() &&
308                (XRE_IsContentProcess() || XRE_IsGPUProcess()));
309 
310     if (XRE_IsContentProcess()) {
311       dom::ContentChild* cc = dom::ContentChild::GetSingleton();
312       Unused << cc->SendGraphicsError(mMessage);
313     } else if (XRE_IsGPUProcess()) {
314       GPUParent* gp = GPUParent::GetSingleton();
315       Unused << gp->SendGraphicsError(mMessage);
316     }
317 
318     return NS_OK;
319   }
320 
321  protected:
322   nsCString mMessage;
323 };
324 
Log(const std::string & aString)325 void CrashStatsLogForwarder::Log(const std::string& aString) {
326   MutexAutoLock lock(mMutex);
327 
328   if (UpdateStringsVector(aString)) {
329     UpdateCrashReport();
330   }
331 
332   // Add it to the parent strings
333   if (!XRE_IsParentProcess()) {
334     nsCString stringToSend(aString.c_str());
335     if (NS_IsMainThread()) {
336       if (XRE_IsContentProcess()) {
337         dom::ContentChild* cc = dom::ContentChild::GetSingleton();
338         Unused << cc->SendGraphicsError(stringToSend);
339       } else if (XRE_IsGPUProcess()) {
340         GPUParent* gp = GPUParent::GetSingleton();
341         Unused << gp->SendGraphicsError(stringToSend);
342       }
343     } else {
344       nsCOMPtr<nsIRunnable> r1 = new LogForwarderEvent(stringToSend);
345       NS_DispatchToMainThread(r1);
346     }
347   }
348 }
349 
350 class CrashTelemetryEvent : public Runnable {
351   virtual ~CrashTelemetryEvent() = default;
352 
353  public:
NS_INLINE_DECL_REFCOUNTING_INHERITED(CrashTelemetryEvent,Runnable)354   NS_INLINE_DECL_REFCOUNTING_INHERITED(CrashTelemetryEvent, Runnable)
355 
356   explicit CrashTelemetryEvent(uint32_t aReason)
357       : mozilla::Runnable("CrashTelemetryEvent"), mReason(aReason) {}
358 
Run()359   NS_IMETHOD Run() override {
360     MOZ_ASSERT(NS_IsMainThread());
361     Telemetry::Accumulate(Telemetry::GFX_CRASH, mReason);
362     return NS_OK;
363   }
364 
365  protected:
366   uint32_t mReason;
367 };
368 
CrashAction(LogReason aReason)369 void CrashStatsLogForwarder::CrashAction(LogReason aReason) {
370 #ifndef RELEASE_OR_BETA
371   // Non-release builds crash by default, but will use telemetry
372   // if this environment variable is present.
373   static bool useTelemetry = gfxEnv::GfxDevCrashTelemetry();
374 #else
375   // Release builds use telemetry by default, but will crash instead
376   // if this environment variable is present.
377   static bool useTelemetry = !gfxEnv::GfxDevCrashMozCrash();
378 #endif
379 
380   if (useTelemetry) {
381     // The callers need to assure that aReason is in the range
382     // that the telemetry call below supports.
383     if (NS_IsMainThread()) {
384       Telemetry::Accumulate(Telemetry::GFX_CRASH, (uint32_t)aReason);
385     } else {
386       nsCOMPtr<nsIRunnable> r1 = new CrashTelemetryEvent((uint32_t)aReason);
387       NS_DispatchToMainThread(r1);
388     }
389   } else {
390     // ignoring aReason, we can get the information we need from the stack
391     MOZ_CRASH("GFX_CRASH");
392   }
393 }
394 
395 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
396 
397 #define GFX_PREF_FALLBACK_USE_CMAPS \
398   "gfx.font_rendering.fallback.always_use_cmaps"
399 
400 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
401 
402 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
403 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
404 
405 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
406 #if defined(XP_MACOSX)
407 #  define GFX_PREF_CORETEXT_SHAPING "gfx.font_rendering.coretext.enabled"
408 #endif
409 
410 #define BIDI_NUMERAL_PREF "bidi.numeral"
411 
412 #define FONT_VARIATIONS_PREF "layout.css.font-variations.enabled"
413 
414 static const char* kObservedPrefs[] = {"gfx.downloadable_fonts.",
415                                        "gfx.font_rendering.", BIDI_NUMERAL_PREF,
416                                        nullptr};
417 
FontPrefChanged(const char * aPref,void * aData)418 static void FontPrefChanged(const char* aPref, void* aData) {
419   MOZ_ASSERT(aPref);
420   NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
421   gfxPlatform::GetPlatform()->FontsPrefsChanged(aPref);
422 }
423 
OnMemoryPressure(layers::MemoryPressureReason aWhy)424 void gfxPlatform::OnMemoryPressure(layers::MemoryPressureReason aWhy) {
425   Factory::PurgeAllCaches();
426   gfxGradientCache::PurgeAllCaches();
427   gfxFontMissingGlyphs::Purge();
428   PurgeSkiaFontCache();
429   if (XRE_IsParentProcess()) {
430     layers::CompositorManagerChild* manager =
431         CompositorManagerChild::GetInstance();
432     if (manager) {
433       manager->SendNotifyMemoryPressure();
434     }
435   }
436 }
437 
gfxPlatform()438 gfxPlatform::gfxPlatform()
439     : mHasVariationFontSupport(false),
440       mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo),
441       mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo),
442       mFrameStatsCollector(this, &gfxPlatform::GetFrameStats),
443       mCMSInfoCollector(this, &gfxPlatform::GetCMSSupportInfo),
444       mDisplayInfoCollector(this, &gfxPlatform::GetDisplayInfo),
445       mCompositorBackend(layers::LayersBackend::LAYERS_NONE),
446       mScreenDepth(0) {
447   mAllowDownloadableFonts = UNINITIALIZED_VALUE;
448   mFallbackUsesCmaps = UNINITIALIZED_VALUE;
449 
450   mWordCacheCharLimit = UNINITIALIZED_VALUE;
451   mWordCacheMaxEntries = UNINITIALIZED_VALUE;
452   mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
453   mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
454   mBidiNumeralOption = UNINITIALIZED_VALUE;
455 
456   InitBackendPrefs(GetBackendPrefs());
457   VRManager::ManagerInit();
458 }
459 
GetPlatform()460 gfxPlatform* gfxPlatform::GetPlatform() {
461   if (!gPlatform) {
462     MOZ_RELEASE_ASSERT(!XRE_IsContentProcess(),
463                        "Content Process should have called InitChild() before "
464                        "first GetPlatform()");
465     Init();
466   }
467   return gPlatform;
468 }
469 
Initialized()470 bool gfxPlatform::Initialized() { return !!gPlatform; }
471 
472 /* static */
InitChild(const ContentDeviceData & aData)473 void gfxPlatform::InitChild(const ContentDeviceData& aData) {
474   MOZ_ASSERT(XRE_IsContentProcess());
475   MOZ_RELEASE_ASSERT(!gPlatform,
476                      "InitChild() should be called before first GetPlatform()");
477   // Make the provided initial ContentDeviceData available to the init
478   // routines, so they don't have to do a sync request from the parent.
479   gContentDeviceInitData = &aData;
480   Init();
481   gContentDeviceInitData = nullptr;
482 }
483 
484 #define WR_DEBUG_PREF "gfx.webrender.debug"
485 
SwapIntervalPrefChangeCallback(const char * aPrefName,void *)486 static void SwapIntervalPrefChangeCallback(const char* aPrefName, void*) {
487   bool egl = Preferences::GetBool("gfx.swap-interval.egl", false);
488   bool glx = Preferences::GetBool("gfx.swap-interval.glx", false);
489   gfxVars::SetSwapIntervalEGL(egl);
490   gfxVars::SetSwapIntervalGLX(glx);
491 }
492 
WebRendeProfilerUIPrefChangeCallback(const char * aPrefName,void *)493 static void WebRendeProfilerUIPrefChangeCallback(const char* aPrefName, void*) {
494   nsCString uiString;
495   if (NS_SUCCEEDED(Preferences::GetCString("gfx.webrender.debug.profiler-ui",
496                                            uiString))) {
497     gfxVars::SetWebRenderProfilerUI(uiString);
498   }
499 }
500 
501 // List of boolean dynamic parameter for WebRender.
502 //
503 // The parameters in this list are:
504 //  - The pref name.
505 //  - The BoolParameter enum variant (see webrender_api/src/lib.rs)
506 //  - A default value.
507 #define WR_BOOL_PARAMETER_LIST(_)                                     \
508   _("gfx.webrender.batched-texture-uploads",                          \
509     wr::BoolParameter::BatchedUploads, true)                          \
510   _("gfx.webrender.draw-calls-for-texture-copy",                      \
511     wr::BoolParameter::DrawCallsForTextureCopy, true)                 \
512   _("gfx.webrender.pbo-uploads", wr::BoolParameter::PboUploads, true) \
513   _("gfx.webrender.multithreading", wr::BoolParameter::Multithreading, true)
514 
WebRenderBoolParameterChangeCallback(const char *,void *)515 static void WebRenderBoolParameterChangeCallback(const char*, void*) {
516   uint32_t bits = 0;
517 
518 #define WR_BOOL_PARAMETER(name, key, default_val) \
519   if (Preferences::GetBool(name, default_val)) {  \
520     bits |= 1 << (uint32_t)key;                   \
521   }
522 
523   WR_BOOL_PARAMETER_LIST(WR_BOOL_PARAMETER)
524 #undef WR_BOOL_PARAMETER
525 
526   gfx::gfxVars::SetWebRenderBoolParameters(bits);
527 }
528 
RegisterWebRenderBoolParamCallback()529 static void RegisterWebRenderBoolParamCallback() {
530 #define WR_BOOL_PARAMETER(name, _key, _default_val) \
531   Preferences::RegisterCallback(WebRenderBoolParameterChangeCallback, name);
532 
533   WR_BOOL_PARAMETER_LIST(WR_BOOL_PARAMETER)
534 #undef WR_BOOL_PARAMETER
535 
536   WebRenderBoolParameterChangeCallback(nullptr, nullptr);
537 }
538 
WebRenderDebugPrefChangeCallback(const char * aPrefName,void *)539 static void WebRenderDebugPrefChangeCallback(const char* aPrefName, void*) {
540   wr::DebugFlags flags{0};
541 #define GFX_WEBRENDER_DEBUG(suffix, bit)                   \
542   if (Preferences::GetBool(WR_DEBUG_PREF suffix, false)) { \
543     flags |= (bit);                                        \
544   }
545 
546   GFX_WEBRENDER_DEBUG(".profiler", wr::DebugFlags::PROFILER_DBG)
547   GFX_WEBRENDER_DEBUG(".render-targets", wr::DebugFlags::RENDER_TARGET_DBG)
548   GFX_WEBRENDER_DEBUG(".texture-cache", wr::DebugFlags::TEXTURE_CACHE_DBG)
549   GFX_WEBRENDER_DEBUG(".gpu-time-queries", wr::DebugFlags::GPU_TIME_QUERIES)
550   GFX_WEBRENDER_DEBUG(".gpu-sample-queries", wr::DebugFlags::GPU_SAMPLE_QUERIES)
551   GFX_WEBRENDER_DEBUG(".disable-batching", wr::DebugFlags::DISABLE_BATCHING)
552   GFX_WEBRENDER_DEBUG(".epochs", wr::DebugFlags::EPOCHS)
553   GFX_WEBRENDER_DEBUG(".smart-profiler", wr::DebugFlags::SMART_PROFILER)
554   GFX_WEBRENDER_DEBUG(".echo-driver-messages",
555                       wr::DebugFlags::ECHO_DRIVER_MESSAGES)
556   GFX_WEBRENDER_DEBUG(".show-overdraw", wr::DebugFlags::SHOW_OVERDRAW)
557   GFX_WEBRENDER_DEBUG(".gpu-cache", wr::DebugFlags::GPU_CACHE_DBG)
558   GFX_WEBRENDER_DEBUG(".texture-cache.clear-evicted",
559                       wr::DebugFlags::TEXTURE_CACHE_DBG_CLEAR_EVICTED)
560   GFX_WEBRENDER_DEBUG(".picture-caching", wr::DebugFlags::PICTURE_CACHING_DBG)
561   GFX_WEBRENDER_DEBUG(".force-picture-invalidation",
562                       wr::DebugFlags::FORCE_PICTURE_INVALIDATION)
563   GFX_WEBRENDER_DEBUG(".primitives", wr::DebugFlags::PRIMITIVE_DBG)
564   // Bit 18 is for the zoom display, which requires the mouse position and thus
565   // currently only works in wrench.
566   GFX_WEBRENDER_DEBUG(".small-screen", wr::DebugFlags::SMALL_SCREEN)
567   GFX_WEBRENDER_DEBUG(".disable-opaque-pass",
568                       wr::DebugFlags::DISABLE_OPAQUE_PASS)
569   GFX_WEBRENDER_DEBUG(".disable-alpha-pass", wr::DebugFlags::DISABLE_ALPHA_PASS)
570   GFX_WEBRENDER_DEBUG(".disable-clip-masks", wr::DebugFlags::DISABLE_CLIP_MASKS)
571   GFX_WEBRENDER_DEBUG(".disable-text-prims", wr::DebugFlags::DISABLE_TEXT_PRIMS)
572   GFX_WEBRENDER_DEBUG(".disable-gradient-prims",
573                       wr::DebugFlags::DISABLE_GRADIENT_PRIMS)
574   GFX_WEBRENDER_DEBUG(".obscure-images", wr::DebugFlags::OBSCURE_IMAGES)
575   GFX_WEBRENDER_DEBUG(".glyph-flashing", wr::DebugFlags::GLYPH_FLASHING)
576   GFX_WEBRENDER_DEBUG(".capture-profiler", wr::DebugFlags::PROFILER_CAPTURE)
577   GFX_WEBRENDER_DEBUG(".window-visibility",
578                       wr::DebugFlags::WINDOW_VISIBILITY_DBG)
579 #undef GFX_WEBRENDER_DEBUG
580 
581   gfx::gfxVars::SetWebRenderDebugFlags(flags.bits);
582 }
583 
WebRenderQualityPrefChangeCallback(const char * aPref,void *)584 static void WebRenderQualityPrefChangeCallback(const char* aPref, void*) {
585   gfxPlatform::GetPlatform()->UpdateForceSubpixelAAWherePossible();
586 }
587 
WebRenderBatchingPrefChangeCallback(const char * aPrefName,void *)588 static void WebRenderBatchingPrefChangeCallback(const char* aPrefName, void*) {
589   uint32_t count = Preferences::GetUint(
590       StaticPrefs::GetPrefName_gfx_webrender_batching_lookback(), 10);
591 
592   gfx::gfxVars::SetWebRenderBatchingLookback(count);
593 }
594 
WebRenderBlobTileSizePrefChangeCallback(const char * aPrefName,void *)595 static void WebRenderBlobTileSizePrefChangeCallback(const char* aPrefName,
596                                                     void*) {
597   uint32_t tileSize = Preferences::GetUint(
598       StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size(), 256);
599   gfx::gfxVars::SetWebRenderBlobTileSize(tileSize);
600 }
601 
WebRenderUploadThresholdPrefChangeCallback(const char * aPrefName,void *)602 static void WebRenderUploadThresholdPrefChangeCallback(const char* aPrefName,
603                                                        void*) {
604   int value = Preferences::GetInt(
605       StaticPrefs::GetPrefName_gfx_webrender_batched_upload_threshold(),
606       512 * 512);
607 
608   gfxVars::SetWebRenderBatchedUploadThreshold(value);
609 }
610 
GetSkiaGlyphCacheSize()611 static uint32_t GetSkiaGlyphCacheSize() {
612   // Only increase font cache size on non-android to save memory.
613 #if !defined(MOZ_WIDGET_ANDROID)
614   // 10mb as the default pref cache size on desktop due to talos perf tweaking.
615   // Chromium uses 20mb and skia default uses 2mb.
616   // We don't need to change the font cache count since we usually
617   // cache thrash due to asian character sets in talos.
618   // Only increase memory on the content process
619   uint32_t cacheSize =
620       StaticPrefs::gfx_content_skia_font_cache_size_AtStartup() * 1024 * 1024;
621   if (mozilla::BrowserTabsRemoteAutostart()) {
622     return XRE_IsContentProcess() ? cacheSize : kDefaultGlyphCacheSize;
623   }
624 
625   return cacheSize;
626 #else
627   return kDefaultGlyphCacheSize;
628 #endif  // MOZ_WIDGET_ANDROID
629 }
630 
631 class WebRenderMemoryReporter final : public nsIMemoryReporter {
632  public:
633   NS_DECL_ISUPPORTS
634   NS_DECL_NSIMEMORYREPORTER
635 
636  private:
637   ~WebRenderMemoryReporter() = default;
638 };
639 
640 // Memory reporter for WebRender.
641 //
642 // The reporting within WebRender is manual and incomplete. We could do a much
643 // more thorough job by depending on the malloc_size_of crate, but integrating
644 // that into WebRender is tricky [1].
645 //
646 // So the idea is to start with manual reporting for the large allocations
647 // detected by DMD, and see how much that can cover in practice (which may
648 // require a few rounds of iteration). If that approach turns out to be
649 // fundamentally insufficient, we can either duplicate more of the
650 // malloc_size_of functionality in WebRender, or deal with the complexity of a
651 // gecko-only crate dependency.
652 //
653 // [1] See https://bugzilla.mozilla.org/show_bug.cgi?id=1480293#c1
654 struct WebRenderMemoryReporterHelper {
WebRenderMemoryReporterHelperWebRenderMemoryReporterHelper655   WebRenderMemoryReporterHelper(nsIHandleReportCallback* aCallback,
656                                 nsISupports* aData)
657       : mCallback(aCallback), mData(aData) {}
658   nsCOMPtr<nsIHandleReportCallback> mCallback;
659   nsCOMPtr<nsISupports> mData;
660 
ReportWebRenderMemoryReporterHelper661   void Report(size_t aBytes, const char* aName) const {
662     nsPrintfCString path("explicit/gfx/webrender/%s", aName);
663     nsCString desc("CPU heap memory used by WebRender"_ns);
664     ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_HEAP);
665   }
666 
ReportTextureWebRenderMemoryReporterHelper667   void ReportTexture(size_t aBytes, const char* aName) const {
668     nsPrintfCString path("gfx/webrender/textures/%s", aName);
669     nsCString desc("GPU texture memory used by WebRender"_ns);
670     ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_OTHER);
671   }
672 
ReportTotalGPUBytesWebRenderMemoryReporterHelper673   void ReportTotalGPUBytes(size_t aBytes) const {
674     nsCString path("gfx/webrender/total-gpu-bytes"_ns);
675     nsCString desc(nsLiteralCString(
676         "Total GPU bytes used by WebRender (should match textures/ sum)"));
677     ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_OTHER);
678   }
679 
ReportInternalWebRenderMemoryReporterHelper680   void ReportInternal(size_t aBytes, nsACString& aPath, nsACString& aDesc,
681                       int32_t aKind) const {
682     // Generally, memory reporters pass the empty string as the process name to
683     // indicate "current process". However, if we're using a GPU process, the
684     // measurements will actually take place in that process, and it's easier to
685     // just note that here rather than trying to invoke the memory reporter in
686     // the GPU process.
687     nsAutoCString processName;
688     if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
689       GPUParent::GetGPUProcessName(processName);
690     }
691 
692     mCallback->Callback(processName, aPath, aKind,
693                         nsIMemoryReporter::UNITS_BYTES, aBytes, aDesc, mData);
694   }
695 };
696 
FinishAsyncMemoryReport()697 static void FinishAsyncMemoryReport() {
698   nsCOMPtr<nsIMemoryReporterManager> imgr =
699       do_GetService("@mozilla.org/memory-reporter-manager;1");
700   if (imgr) {
701     imgr->EndReport();
702   }
703 }
704 
705 // clang-format off
706 // (For some reason, clang-format gets the second macro right, but totally mangles the first).
707 #define REPORT_INTERNER(id)                      \
708   helper.Report(aReport.interning.interners.id, \
709                 "interning/" #id "/interners");
710 // clang-format on
711 
712 #define REPORT_DATA_STORE(id)                     \
713   helper.Report(aReport.interning.data_stores.id, \
714                 "interning/" #id "/data-stores");
715 
NS_IMPL_ISUPPORTS(WebRenderMemoryReporter,nsIMemoryReporter)716 NS_IMPL_ISUPPORTS(WebRenderMemoryReporter, nsIMemoryReporter)
717 
718 NS_IMETHODIMP
719 WebRenderMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
720                                         nsISupports* aData, bool aAnonymize) {
721   MOZ_ASSERT(XRE_IsParentProcess());
722   MOZ_ASSERT(NS_IsMainThread());
723   layers::CompositorManagerChild* manager =
724       CompositorManagerChild::GetInstance();
725   if (!manager) {
726     FinishAsyncMemoryReport();
727     return NS_OK;
728   }
729 
730   WebRenderMemoryReporterHelper helper(aHandleReport, aData);
731   manager->SendReportMemory(
732       [=](wr::MemoryReport aReport) {
733         // CPU Memory.
734         helper.Report(aReport.clip_stores, "clip-stores");
735         helper.Report(aReport.gpu_cache_metadata, "gpu-cache/metadata");
736         helper.Report(aReport.gpu_cache_cpu_mirror, "gpu-cache/cpu-mirror");
737         helper.Report(aReport.render_tasks, "render-tasks");
738         helper.Report(aReport.hit_testers, "hit-testers");
739         helper.Report(aReport.fonts, "resource-cache/fonts");
740         helper.Report(aReport.weak_fonts, "resource-cache/weak-fonts");
741         helper.Report(aReport.images, "resource-cache/images");
742         helper.Report(aReport.rasterized_blobs,
743                       "resource-cache/rasterized-blobs");
744         helper.Report(aReport.texture_cache_structures,
745                       "texture-cache/structures");
746         helper.Report(aReport.shader_cache, "shader-cache");
747         helper.Report(aReport.display_list, "display-list");
748         helper.Report(aReport.swgl, "swgl");
749         helper.Report(aReport.upload_staging_memory, "upload-stagin-memory");
750 
751         WEBRENDER_FOR_EACH_INTERNER(REPORT_INTERNER);
752         WEBRENDER_FOR_EACH_INTERNER(REPORT_DATA_STORE);
753 
754         // GPU Memory.
755         helper.ReportTexture(aReport.gpu_cache_textures, "gpu-cache");
756         helper.ReportTexture(aReport.vertex_data_textures, "vertex-data");
757         helper.ReportTexture(aReport.render_target_textures, "render-targets");
758         helper.ReportTexture(aReport.depth_target_textures, "depth-targets");
759         helper.ReportTexture(aReport.picture_tile_textures, "picture-tiles");
760         helper.ReportTexture(aReport.atlas_textures, "texture-cache/atlas");
761         helper.ReportTexture(aReport.standalone_textures,
762                              "texture-cache/standalone");
763         helper.ReportTexture(aReport.texture_upload_pbos,
764                              "texture-upload-pbos");
765         helper.ReportTexture(aReport.swap_chain, "swap-chains");
766         helper.ReportTexture(aReport.render_texture_hosts,
767                              "render-texture-hosts");
768         helper.ReportTexture(aReport.upload_staging_textures,
769                              "upload-staging-textures");
770 
771         FinishAsyncMemoryReport();
772       },
773       [](mozilla::ipc::ResponseRejectReason&& aReason) {
774         FinishAsyncMemoryReport();
775       });
776 
777   return NS_OK;
778 }
779 
780 #undef REPORT_INTERNER
781 #undef REPORT_DATA_STORE
782 
FrameRatePrefChanged(const char * aPref,void *)783 static void FrameRatePrefChanged(const char* aPref, void*) {
784   int32_t newRate = gfxPlatform::ForceSoftwareVsync()
785                         ? gfxPlatform::GetSoftwareVsyncRate()
786                         : -1;
787   if (newRate != gLastUsedFrameRate) {
788     gLastUsedFrameRate = newRate;
789     gfxPlatform::ReInitFrameRate();
790   }
791 }
792 
Init()793 void gfxPlatform::Init() {
794   MOZ_RELEASE_ASSERT(!XRE_IsGPUProcess(), "GFX: Not allowed in GPU process.");
795   MOZ_RELEASE_ASSERT(!XRE_IsRDDProcess(), "GFX: Not allowed in RDD process.");
796   MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
797 
798   if (gEverInitialized) {
799     MOZ_CRASH("Already started???");
800   }
801   gEverInitialized = true;
802 
803   gfxVars::Initialize();
804 
805   gfxConfig::Init();
806 
807   if (XRE_IsParentProcess()) {
808     GPUProcessManager::Initialize();
809     RDDProcessManager::Initialize();
810 
811     nsCOMPtr<nsIFile> file;
812     nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
813     if (NS_FAILED(rv)) {
814       gfxVars::SetGREDirectory(nsString());
815     } else {
816       nsAutoString path;
817       file->GetPath(path);
818       gfxVars::SetGREDirectory(nsString(path));
819     }
820   }
821 
822   if (XRE_IsParentProcess()) {
823     nsCOMPtr<nsIFile> profDir;
824     nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
825                                          getter_AddRefs(profDir));
826     if (NS_FAILED(rv)) {
827       gfxVars::SetProfDirectory(nsString());
828     } else {
829       nsAutoString path;
830       profDir->GetPath(path);
831       gfxVars::SetProfDirectory(nsString(path));
832     }
833 
834     nsAutoCString path;
835     Preferences::GetCString("layers.windowrecording.path", path);
836     gfxVars::SetLayersWindowRecordingPath(path);
837 
838     if (gFxREmbedded) {
839       gfxVars::SetFxREmbedded(true);
840     }
841   }
842 
843   // Drop a note in the crash report if we end up forcing an option that could
844   // destabilize things.  New items should be appended at the end (of an
845   // existing or in a new section), so that we don't have to know the version to
846   // interpret these cryptic strings.
847   {
848     nsAutoCString forcedPrefs;
849     // D2D prefs
850     forcedPrefs.AppendPrintf(
851         "FP(D%d%d", StaticPrefs::gfx_direct2d_disabled_AtStartup(),
852         StaticPrefs::gfx_direct2d_force_enabled_AtStartup());
853     // Layers prefs
854     forcedPrefs.AppendPrintf(
855         "-L%d%d%d%d",
856         StaticPrefs::layers_amd_switchable_gfx_enabled_AtStartup(),
857         StaticPrefs::layers_acceleration_disabled_AtStartup_DoNotUseDirectly(),
858         StaticPrefs::
859             layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly(),
860         StaticPrefs::layers_d3d11_force_warp_AtStartup());
861     // WebGL prefs
862     forcedPrefs.AppendPrintf(
863         "-W%d%d%d%d%d%d%d%d", StaticPrefs::webgl_angle_force_d3d11(),
864         StaticPrefs::webgl_angle_force_warp(), StaticPrefs::webgl_disabled(),
865         StaticPrefs::webgl_disable_angle(), StaticPrefs::webgl_dxgl_enabled(),
866         StaticPrefs::webgl_force_enabled(),
867         StaticPrefs::webgl_force_layers_readback(),
868         StaticPrefs::webgl_msaa_force());
869     // Prefs that don't fit into any of the other sections
870     forcedPrefs.AppendPrintf("-T%d%d%d) ",
871                              StaticPrefs::gfx_android_rgb16_force_AtStartup(),
872                              StaticPrefs::gfx_canvas_accelerated(),
873                              StaticPrefs::layers_force_shmem_tiles_AtStartup());
874     ScopedGfxFeatureReporter::AppNote(forcedPrefs);
875   }
876 
877   InitMoz2DLogging();
878 
879   /* Initialize the GfxInfo service.
880    * Note: we can't call functions on GfxInfo that depend
881    * on gPlatform until after it has been initialized
882    * below. GfxInfo initialization annotates our
883    * crash reports so we want to do it before
884    * we try to load any drivers and do device detection
885    * incase that code crashes. See bug #591561. */
886   nsCOMPtr<nsIGfxInfo> gfxInfo;
887   /* this currently will only succeed on Windows */
888   gfxInfo = components::GfxInfo::Service();
889 
890   if (XRE_IsParentProcess()) {
891     // Some gfxVars must be initialized prior gPlatform for coherent results.
892     gfxVars::SetDXInterop2Blocked(IsDXInterop2Blocked());
893     gfxVars::SetDXNV12Blocked(IsDXNV12Blocked());
894     gfxVars::SetDXP010Blocked(IsDXP010Blocked());
895     gfxVars::SetDXP016Blocked(IsDXP016Blocked());
896   }
897 
898 #if defined(XP_WIN)
899   gPlatform = new gfxWindowsPlatform;
900 #elif defined(XP_MACOSX)
901   gPlatform = new gfxPlatformMac;
902 #elif defined(MOZ_WIDGET_GTK)
903   gPlatform = new gfxPlatformGtk;
904 #elif defined(ANDROID)
905   gPlatform = new gfxAndroidPlatform;
906 #else
907 #  error "No gfxPlatform implementation available"
908 #endif
909   gPlatform->PopulateScreenInfo();
910   gPlatform->InitAcceleration();
911   gPlatform->InitWebRenderConfig();
912 
913   gPlatform->InitWebGLConfig();
914   gPlatform->InitWebGPUConfig();
915   gPlatform->InitWindowOcclusionConfig();
916 
917   // When using WebRender, we defer initialization of the D3D11 devices until
918   // the (rare) cases where they're used. Note that the GPU process where
919   // WebRender runs doesn't initialize gfxPlatform and performs explicit
920   // initialization of the bits it needs.
921   if (!UseWebRender()
922 #if defined(XP_WIN)
923       || (UseWebRender() && XRE_IsParentProcess() &&
924           !gfxConfig::IsEnabled(Feature::GPU_PROCESS) &&
925           StaticPrefs::
926               gfx_webrender_enabled_no_gpu_process_with_angle_win_AtStartup())
927 #endif
928   ) {
929     gPlatform->EnsureDevicesInitialized();
930   }
931 
932   if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
933     GPUProcessManager* gpu = GPUProcessManager::Get();
934     gpu->LaunchGPUProcess();
935   }
936 
937   if (XRE_IsParentProcess()) {
938     nsAutoCString allowlist;
939     Preferences::GetCString("gfx.offscreencanvas.domain-allowlist", allowlist);
940     gfxVars::SetOffscreenCanvasDomainAllowlist(allowlist);
941   }
942 
943   gLastUsedFrameRate = ForceSoftwareVsync() ? GetSoftwareVsyncRate() : -1;
944   Preferences::RegisterCallback(
945       FrameRatePrefChanged,
946       nsDependentCString(StaticPrefs::GetPrefName_layout_frame_rate()));
947   // Set up the vsync source for the parent process.
948   ReInitFrameRate();
949 
950   // Create the sRGB to output display profile transforms. They can be accessed
951   // off the main thread so we want to avoid a race condition.
952   InitializeCMS();
953 
954   SkGraphics::Init();
955 #ifdef MOZ_ENABLE_FREETYPE
956   SkInitCairoFT(gPlatform->FontHintingEnabled());
957 #endif
958 
959   InitLayersIPC();
960 
961   gPlatform->mHasVariationFontSupport = gPlatform->CheckVariationFontSupport();
962 
963   // This *create* the platform font list instance, but may not *initialize* it
964   // yet if the gfx.font-list.lazy-init.enabled pref is set. The first *use*
965   // of the list will ensure it is initialized.
966   if (!gPlatform->CreatePlatformFontList()) {
967     MOZ_CRASH("Could not initialize gfxPlatformFontList");
968   }
969 
970   gPlatform->mScreenReferenceDrawTarget =
971       gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
972                                                   SurfaceFormat::B8G8R8A8);
973   if (!gPlatform->mScreenReferenceDrawTarget ||
974       !gPlatform->mScreenReferenceDrawTarget->IsValid()) {
975     // If TDR is detected, create a draw target with software backend
976     // and it should be replaced later when the process gets the device
977     // reset notification.
978     if (!gPlatform->DidRenderingDeviceReset()) {
979       gfxCriticalError() << "Could not initialize mScreenReferenceDrawTarget";
980     }
981   }
982 
983   if (NS_FAILED(gfxFontCache::Init())) {
984     MOZ_CRASH("Could not initialize gfxFontCache");
985   }
986 
987   Preferences::RegisterPrefixCallbacks(FontPrefChanged, kObservedPrefs);
988 
989   GLContext::PlatformStartup();
990 
991   // Listen to memory pressure event so we can purge DrawTarget caches
992   gPlatform->mMemoryPressureObserver =
993       layers::MemoryPressureObserver::Create(gPlatform);
994 
995   // Request the imgITools service, implicitly initializing ImageLib.
996   nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
997   if (!imgTools) {
998     MOZ_CRASH("Could not initialize ImageLib");
999   }
1000 
1001   RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
1002   if (XRE_IsParentProcess() && UseWebRender()) {
1003     RegisterStrongAsyncMemoryReporter(new WebRenderMemoryReporter());
1004   }
1005 
1006   RegisterStrongMemoryReporter(new SkMemoryReporter());
1007 
1008   uint32_t skiaCacheSize = GetSkiaGlyphCacheSize();
1009   if (skiaCacheSize != kDefaultGlyphCacheSize) {
1010     SkGraphics::SetFontCacheLimit(skiaCacheSize);
1011   }
1012 
1013   InitNullMetadata();
1014   InitOpenGLConfig();
1015 
1016   if (XRE_IsParentProcess()) {
1017     Preferences::Unlock(FONT_VARIATIONS_PREF);
1018     if (!gPlatform->HasVariationFontSupport()) {
1019       // Ensure variation fonts are disabled and the pref is locked.
1020       Preferences::SetBool(FONT_VARIATIONS_PREF, false, PrefValueKind::Default);
1021       Preferences::SetBool(FONT_VARIATIONS_PREF, false);
1022       Preferences::Lock(FONT_VARIATIONS_PREF);
1023     }
1024   }
1025 
1026   if (XRE_IsParentProcess()) {
1027     ReportTelemetry();
1028   }
1029 
1030   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1031   if (obs) {
1032     obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr);
1033   }
1034 }
1035 
ReportTelemetry()1036 void gfxPlatform::ReportTelemetry() {
1037   MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
1038                      "GFX: Only allowed to be called from parent process.");
1039 
1040   nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
1041   nsTArray<uint32_t> displayWidths;
1042   nsTArray<uint32_t> displayHeights;
1043   gfxInfo->GetDisplayWidth(displayWidths);
1044   gfxInfo->GetDisplayHeight(displayHeights);
1045 
1046   uint32_t displayCount = displayWidths.Length();
1047   uint32_t displayWidth = displayWidths.Length() > 0 ? displayWidths[0] : 0;
1048   uint32_t displayHeight = displayHeights.Length() > 0 ? displayHeights[0] : 0;
1049   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_DISPLAY_COUNT, displayCount);
1050   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_DISPLAY_PRIMARY_HEIGHT,
1051                        displayHeight);
1052   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_DISPLAY_PRIMARY_WIDTH,
1053                        displayWidth);
1054 
1055   nsString adapterDesc;
1056   gfxInfo->GetAdapterDescription(adapterDesc);
1057   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DESCRIPTION,
1058                        adapterDesc);
1059 
1060   nsString adapterVendorId;
1061   gfxInfo->GetAdapterVendorID(adapterVendorId);
1062   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_VENDOR_ID,
1063                        adapterVendorId);
1064 
1065   nsString adapterDeviceId;
1066   gfxInfo->GetAdapterDeviceID(adapterDeviceId);
1067   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DEVICE_ID,
1068                        adapterDeviceId);
1069 
1070   nsString adapterSubsystemId;
1071   gfxInfo->GetAdapterSubsysID(adapterSubsystemId);
1072   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_SUBSYSTEM_ID,
1073                        adapterSubsystemId);
1074 
1075   uint32_t adapterRam = 0;
1076   gfxInfo->GetAdapterRAM(&adapterRam);
1077   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_RAM, adapterRam);
1078 
1079   nsString adapterDriver;
1080   gfxInfo->GetAdapterDriver(adapterDriver);
1081   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DRIVER_FILES,
1082                        adapterDriver);
1083 
1084   nsString adapterDriverVendor;
1085   gfxInfo->GetAdapterDriverVendor(adapterDriverVendor);
1086   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DRIVER_VENDOR,
1087                        adapterDriverVendor);
1088 
1089   nsString adapterDriverVersion;
1090   gfxInfo->GetAdapterDriverVersion(adapterDriverVersion);
1091   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DRIVER_VERSION,
1092                        adapterDriverVersion);
1093 
1094   nsString adapterDriverDate;
1095   gfxInfo->GetAdapterDriverDate(adapterDriverDate);
1096   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DRIVER_DATE,
1097                        adapterDriverDate);
1098 
1099   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_HEADLESS, IsHeadless());
1100 }
1101 
IsFeatureSupported(long aFeature,bool aDefault)1102 static bool IsFeatureSupported(long aFeature, bool aDefault) {
1103   nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
1104   nsCString blockId;
1105   int32_t status;
1106   if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, blockId, &status))) {
1107     return aDefault;
1108   }
1109   return status == nsIGfxInfo::FEATURE_STATUS_OK;
1110 }
1111 
1112 /* static*/
IsDXInterop2Blocked()1113 bool gfxPlatform::IsDXInterop2Blocked() {
1114   return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_INTEROP2, false);
1115 }
1116 
1117 /* static*/
IsDXNV12Blocked()1118 bool gfxPlatform::IsDXNV12Blocked() {
1119   return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_NV12, false);
1120 }
1121 
1122 /* static*/
IsDXP010Blocked()1123 bool gfxPlatform::IsDXP010Blocked() {
1124   return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_P010, false);
1125 }
1126 
1127 /* static*/
IsDXP016Blocked()1128 bool gfxPlatform::IsDXP016Blocked() {
1129   return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_P016, false);
1130 }
1131 
1132 /* static */
MaxTextureSize()1133 int32_t gfxPlatform::MaxTextureSize() {
1134   // Make sure we don't completely break rendering because of a typo in the
1135   // pref or whatnot.
1136   const int32_t kMinSizePref = 2048;
1137   return std::max(
1138       kMinSizePref,
1139       StaticPrefs::gfx_max_texture_size_AtStartup_DoNotUseDirectly());
1140 }
1141 
1142 /* static */
MaxAllocSize()1143 int32_t gfxPlatform::MaxAllocSize() {
1144   // Make sure we don't completely break rendering because of a typo in the
1145   // pref or whatnot.
1146   const int32_t kMinAllocPref = 10000000;
1147   return std::max(kMinAllocPref,
1148                   StaticPrefs::gfx_max_alloc_size_AtStartup_DoNotUseDirectly());
1149 }
1150 
1151 /* static */
InitMoz2DLogging()1152 void gfxPlatform::InitMoz2DLogging() {
1153   auto fwd = new CrashStatsLogForwarder(
1154       CrashReporter::Annotation::GraphicsCriticalError);
1155   fwd->SetCircularBufferSize(StaticPrefs::gfx_logging_crash_length_AtStartup());
1156 
1157   mozilla::gfx::Config cfg;
1158   cfg.mLogForwarder = fwd;
1159   cfg.mMaxTextureSize = gfxPlatform::MaxTextureSize();
1160   cfg.mMaxAllocSize = gfxPlatform::MaxAllocSize();
1161 
1162   gfx::Factory::Init(cfg);
1163 }
1164 
1165 /* static */
IsHeadless()1166 bool gfxPlatform::IsHeadless() {
1167   static bool initialized = false;
1168   static bool headless = false;
1169   if (!initialized) {
1170     initialized = true;
1171     headless = PR_GetEnv("MOZ_HEADLESS");
1172   }
1173   return headless;
1174 }
1175 
1176 /* static */
UseWebRender()1177 bool gfxPlatform::UseWebRender() { return gfx::gfxVars::UseWebRender(); }
1178 
1179 /* static */
UseRemoteCanvas()1180 bool gfxPlatform::UseRemoteCanvas() {
1181   return XRE_IsContentProcess() && gfx::gfxVars::RemoteCanvasEnabled();
1182 }
1183 
1184 /* static */
IsBackendAccelerated(const mozilla::gfx::BackendType aBackendType)1185 bool gfxPlatform::IsBackendAccelerated(
1186     const mozilla::gfx::BackendType aBackendType) {
1187   return aBackendType == BackendType::DIRECT2D ||
1188          aBackendType == BackendType::DIRECT2D1_1;
1189 }
1190 
1191 /* static */
CanMigrateMacGPUs()1192 bool gfxPlatform::CanMigrateMacGPUs() {
1193   int32_t pMigration = StaticPrefs::gfx_compositor_gpu_migration();
1194 
1195   bool forceDisable = pMigration == 0;
1196   bool forceEnable = pMigration == 2;
1197 
1198   return forceEnable || !forceDisable;
1199 }
1200 
1201 static bool sLayersIPCIsUp = false;
1202 
1203 /* static */
InitNullMetadata()1204 void gfxPlatform::InitNullMetadata() {
1205   ScrollMetadata::sNullMetadata = new ScrollMetadata();
1206   ClearOnShutdown(&ScrollMetadata::sNullMetadata);
1207 }
1208 
Shutdown()1209 void gfxPlatform::Shutdown() {
1210   // In some cases, gPlatform may not be created but Shutdown() called,
1211   // e.g., during xpcshell tests.
1212   if (!gPlatform) {
1213     return;
1214   }
1215 
1216   MOZ_ASSERT(!sLayersIPCIsUp);
1217 
1218   // These may be called before the corresponding subsystems have actually
1219   // started up. That's OK, they can handle it.
1220   gfxFontCache::Shutdown();
1221   gfxGradientCache::Shutdown();
1222   gfxAlphaBoxBlur::ShutdownBlurCache();
1223   gfxGraphiteShaper::Shutdown();
1224   gfxPlatformFontList::Shutdown();
1225   gfxFontMissingGlyphs::Shutdown();
1226 
1227   // Free the various non-null transforms and loaded profiles
1228   ShutdownCMS();
1229 
1230   Preferences::UnregisterPrefixCallbacks(FontPrefChanged, kObservedPrefs);
1231 
1232   NS_ASSERTION(gPlatform->mMemoryPressureObserver,
1233                "mMemoryPressureObserver has already gone");
1234   if (gPlatform->mMemoryPressureObserver) {
1235     gPlatform->mMemoryPressureObserver->Unregister();
1236     gPlatform->mMemoryPressureObserver = nullptr;
1237   }
1238 
1239   if (XRE_IsParentProcess()) {
1240     gPlatform->mVsyncSource->Shutdown();
1241   }
1242 
1243   gPlatform->mVsyncSource = nullptr;
1244 
1245   // Shut down the default GL context provider.
1246   GLContextProvider::Shutdown();
1247 
1248 #if defined(XP_WIN)
1249   // The above shutdown calls operate on the available context providers on
1250   // most platforms.  Windows is a "special snowflake", though, and has three
1251   // context providers available, so we have to shut all of them down.
1252   // We should only support the default GL provider on Windows; then, this
1253   // could go away. Unfortunately, we currently support WGL (the default) for
1254   // WebGL on Optimus.
1255   GLContextProviderEGL::Shutdown();
1256 #endif
1257 
1258   if (XRE_IsParentProcess()) {
1259     GPUProcessManager::Shutdown();
1260     VRProcessManager::Shutdown();
1261     RDDProcessManager::Shutdown();
1262   }
1263 
1264   gfx::Factory::ShutDown();
1265   gfxVars::Shutdown();
1266   gfxFont::DestroySingletons();
1267 
1268   gfxConfig::Shutdown();
1269 
1270   gPlatform->WillShutdown();
1271 
1272   delete gPlatform;
1273   gPlatform = nullptr;
1274 }
1275 
1276 /* static */
InitLayersIPC()1277 void gfxPlatform::InitLayersIPC() {
1278   if (sLayersIPCIsUp) {
1279     return;
1280   }
1281   sLayersIPCIsUp = true;
1282 
1283   if (XRE_IsParentProcess()) {
1284 #if defined(XP_WIN)
1285     if (gfxConfig::IsEnabled(gfx::Feature::WINDOW_OCCLUSION)) {
1286       widget::WinWindowOcclusionTracker::Ensure();
1287     }
1288 #endif
1289     if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS) && UseWebRender()) {
1290       wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());
1291       image::ImageMemoryReporter::InitForWebRender();
1292     }
1293 
1294     layers::CompositorThreadHolder::Start();
1295   }
1296 }
1297 
1298 /* static */
ShutdownLayersIPC()1299 void gfxPlatform::ShutdownLayersIPC() {
1300   if (!sLayersIPCIsUp) {
1301     return;
1302   }
1303   sLayersIPCIsUp = false;
1304 
1305   if (XRE_IsContentProcess()) {
1306     gfx::VRManagerChild::ShutDown();
1307     gfx::CanvasManagerChild::Shutdown();
1308     // cf bug 1215265.
1309     if (StaticPrefs::layers_child_process_shutdown()) {
1310       layers::CompositorManagerChild::Shutdown();
1311       layers::ImageBridgeChild::ShutDown();
1312     }
1313 
1314   } else if (XRE_IsParentProcess()) {
1315     gfx::VRManagerChild::ShutDown();
1316     gfx::CanvasManagerChild::Shutdown();
1317     layers::CompositorManagerChild::Shutdown();
1318     layers::ImageBridgeChild::ShutDown();
1319     // This could be running on either the Compositor or the Renderer thread.
1320     gfx::CanvasManagerParent::Shutdown();
1321     // This has to happen after shutting down the child protocols.
1322     layers::CompositorThreadHolder::Shutdown();
1323     image::ImageMemoryReporter::ShutdownForWebRender();
1324     // There is a case that RenderThread exists when UseWebRender() is
1325     // false. This could happen when WebRender was fallbacked to compositor.
1326     if (wr::RenderThread::Get()) {
1327       wr::RenderThread::ShutDown();
1328 
1329       Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback,
1330                                       WR_DEBUG_PREF);
1331       Preferences::UnregisterCallback(WebRendeProfilerUIPrefChangeCallback,
1332                                       "gfx.webrender.debug.profiler-ui");
1333       Preferences::UnregisterCallback(
1334           WebRenderBlobTileSizePrefChangeCallback,
1335           nsDependentCString(
1336               StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size()));
1337     }
1338 #if defined(XP_WIN)
1339     widget::WinWindowOcclusionTracker::ShutDown();
1340 #endif
1341   } else {
1342     // TODO: There are other kind of processes and we should make sure gfx
1343     // stuff is either not created there or shut down properly.
1344   }
1345 }
1346 
WillShutdown()1347 void gfxPlatform::WillShutdown() {
1348   // Destoy these first in case they depend on backend-specific resources.
1349   // Otherwise, the backend's destructor would be called before the
1350   // base gfxPlatform destructor.
1351   mScreenReferenceSurface = nullptr;
1352   mScreenReferenceDrawTarget = nullptr;
1353 
1354   // Always clear out the Skia font cache here, in case it is referencing any
1355   // SharedFTFaces that would otherwise outlive destruction of the FT_Library
1356   // that owns them.
1357   SkGraphics::PurgeFontCache();
1358 
1359   // The cairo folks think we should only clean up in debug builds,
1360   // but we're generally in the habit of trying to shut down as
1361   // cleanly as possible even in production code, so call this
1362   // cairo_debug_* function unconditionally.
1363   //
1364   // because cairo can assert and thus crash on shutdown, don't do this in
1365   // release builds
1366 #ifdef NS_FREE_PERMANENT_DATA
1367   cairo_debug_reset_static_data();
1368 #endif
1369 }
1370 
1371 gfxPlatform::~gfxPlatform() = default;
1372 
1373 /* static */
CreateDrawTargetForSurface(gfxASurface * aSurface,const IntSize & aSize)1374 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForSurface(
1375     gfxASurface* aSurface, const IntSize& aSize) {
1376   SurfaceFormat format = aSurface->GetSurfaceFormat();
1377   RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(
1378       aSurface->CairoSurface(), aSize, &format);
1379   if (!drawTarget) {
1380     gfxWarning() << "gfxPlatform::CreateDrawTargetForSurface failed in "
1381                     "CreateDrawTargetForCairoSurface";
1382     return nullptr;
1383   }
1384   return drawTarget.forget();
1385 }
1386 
1387 cairo_user_data_key_t kSourceSurface;
1388 
1389 /**
1390  * Record the backend that was used to construct the SourceSurface.
1391  * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
1392  * we check to make sure the DrawTarget's backend matches the backend
1393  * for the cached SourceSurface, and only use it if they match. This
1394  * can avoid expensive and unnecessary readbacks.
1395  */
1396 struct SourceSurfaceUserData {
1397   RefPtr<SourceSurface> mSrcSurface;
1398   BackendType mBackendType;
1399 };
1400 
SourceBufferDestroy(void * srcSurfUD)1401 static void SourceBufferDestroy(void* srcSurfUD) {
1402   delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
1403 }
1404 
1405 UserDataKey kThebesSurface;
1406 
1407 struct DependentSourceSurfaceUserData {
1408   RefPtr<gfxASurface> mSurface;
1409 };
1410 
SourceSurfaceDestroyed(void * aData)1411 static void SourceSurfaceDestroyed(void* aData) {
1412   delete static_cast<DependentSourceSurfaceUserData*>(aData);
1413 }
1414 
ClearSourceSurfaceForSurface(gfxASurface * aSurface)1415 void gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface* aSurface) {
1416   aSurface->SetData(&kSourceSurface, nullptr, nullptr);
1417 }
1418 
1419 /* static */
GetSourceSurfaceForSurface(RefPtr<DrawTarget> aTarget,gfxASurface * aSurface,bool aIsPlugin)1420 already_AddRefed<SourceSurface> gfxPlatform::GetSourceSurfaceForSurface(
1421     RefPtr<DrawTarget> aTarget, gfxASurface* aSurface, bool aIsPlugin) {
1422   if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
1423     return nullptr;
1424   }
1425 
1426   if (!aTarget) {
1427     aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
1428   }
1429 
1430   void* userData = aSurface->GetData(&kSourceSurface);
1431 
1432   if (userData) {
1433     SourceSurfaceUserData* surf = static_cast<SourceSurfaceUserData*>(userData);
1434 
1435     if (surf->mSrcSurface->IsValid() &&
1436         surf->mBackendType == aTarget->GetBackendType()) {
1437       RefPtr<SourceSurface> srcSurface(surf->mSrcSurface);
1438       return srcSurface.forget();
1439     }
1440     // We can just continue here as when setting new user data the destroy
1441     // function will be called for the old user data.
1442   }
1443 
1444   SurfaceFormat format = aSurface->GetSurfaceFormat();
1445 
1446   if (aTarget->GetBackendType() == BackendType::CAIRO) {
1447     // If we're going to be used with a CAIRO DrawTarget, then just create a
1448     // SourceSurfaceCairo since we don't know the underlying type of the CAIRO
1449     // DrawTarget and can't pick a better surface type. Doing this also avoids
1450     // readback of aSurface's surface into memory if, for example, aSurface
1451     // wraps an xlib cairo surface (which can be important to avoid a major
1452     // slowdown).
1453     //
1454     // We return here regardless of whether CreateSourceSurfaceFromNativeSurface
1455     // succeeds or not since we don't expect to be able to do any better below
1456     // if it fails.
1457     //
1458     // Note that the returned SourceSurfaceCairo holds a strong reference to
1459     // the cairo_surface_t* that it wraps, which essencially means it holds a
1460     // strong reference to aSurface since aSurface shares its
1461     // cairo_surface_t*'s reference count variable. As a result we can't cache
1462     // srcBuffer on aSurface (see below) since aSurface would then hold a
1463     // strong reference back to srcBuffer, creating a reference loop and a
1464     // memory leak. Not caching is fine since wrapping is cheap enough (no
1465     // copying) so we can just wrap again next time we're called.
1466     return Factory::CreateSourceSurfaceForCairoSurface(
1467         aSurface->CairoSurface(), aSurface->GetSize(), format);
1468   }
1469 
1470   RefPtr<SourceSurface> srcBuffer;
1471 
1472   // Currently no other DrawTarget types implement
1473   // CreateSourceSurfaceFromNativeSurface
1474 
1475   if (!srcBuffer) {
1476     // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
1477     // the same data, then optimize it for aTarget:
1478     RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface);
1479     if (surf) {
1480       srcBuffer = aIsPlugin
1481                       ? aTarget->OptimizeSourceSurfaceForUnknownAlpha(surf)
1482                       : aTarget->OptimizeSourceSurface(surf);
1483 
1484       if (srcBuffer == surf) {
1485         // GetWrappedDataSourceSurface returns a SourceSurface that holds a
1486         // strong reference to aSurface since it wraps aSurface's data and
1487         // needs it to stay alive. As a result we can't cache srcBuffer on
1488         // aSurface (below) since aSurface would then hold a strong reference
1489         // back to srcBuffer, creating a reference loop and a memory leak. Not
1490         // caching is fine since wrapping is cheap enough (no copying) so we
1491         // can just wrap again next time we're called.
1492         //
1493         // Note that the check below doesn't catch this since srcBuffer will be
1494         // a SourceSurfaceRawData object (even if aSurface is not a
1495         // gfxImageSurface object), which is why we need this separate check.
1496         return srcBuffer.forget();
1497       }
1498     }
1499   }
1500 
1501   if (!srcBuffer) {
1502     MOZ_ASSERT(aTarget->GetBackendType() != BackendType::CAIRO,
1503                "We already tried CreateSourceSurfaceFromNativeSurface with a "
1504                "DrawTargetCairo above");
1505     // We've run out of performant options. We now try creating a SourceSurface
1506     // using a temporary DrawTargetCairo and then optimizing it to aTarget's
1507     // actual type. The CreateSourceSurfaceFromNativeSurface() call will
1508     // likely create a DataSourceSurface (possibly involving copying and/or
1509     // readback), and the OptimizeSourceSurface may well copy again and upload
1510     // to the GPU. So, while this code path is rarely hit, hitting it may be
1511     // very slow.
1512     srcBuffer = Factory::CreateSourceSurfaceForCairoSurface(
1513         aSurface->CairoSurface(), aSurface->GetSize(), format);
1514     if (srcBuffer) {
1515       srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer);
1516     }
1517   }
1518 
1519   if (!srcBuffer) {
1520     return nullptr;
1521   }
1522 
1523   if ((srcBuffer->GetType() == SurfaceType::CAIRO &&
1524        static_cast<SourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1525            aSurface->CairoSurface()) ||
1526       (srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE &&
1527        static_cast<DataSourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1528            aSurface->CairoSurface())) {
1529     // See the "Note that the returned SourceSurfaceCairo..." comment above.
1530     return srcBuffer.forget();
1531   }
1532 
1533   // Add user data to aSurface so we can cache lookups in the future.
1534   auto* srcSurfUD = new SourceSurfaceUserData;
1535   srcSurfUD->mBackendType = aTarget->GetBackendType();
1536   srcSurfUD->mSrcSurface = srcBuffer;
1537   aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
1538 
1539   return srcBuffer.forget();
1540 }
1541 
GetWrappedDataSourceSurface(gfxASurface * aSurface)1542 already_AddRefed<DataSourceSurface> gfxPlatform::GetWrappedDataSourceSurface(
1543     gfxASurface* aSurface) {
1544   RefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
1545   if (!image) {
1546     return nullptr;
1547   }
1548   RefPtr<DataSourceSurface> result = Factory::CreateWrappingDataSourceSurface(
1549       image->Data(), image->Stride(), image->GetSize(),
1550       ImageFormatToSurfaceFormat(image->Format()));
1551 
1552   if (!result) {
1553     return nullptr;
1554   }
1555 
1556   // If we wrapped the underlying data of aSurface, then we need to add user
1557   // data to make sure aSurface stays alive until we are done with the data.
1558   auto* srcSurfUD = new DependentSourceSurfaceUserData;
1559   srcSurfUD->mSurface = aSurface;
1560   result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
1561 
1562   return result.forget();
1563 }
1564 
PopulateScreenInfo()1565 void gfxPlatform::PopulateScreenInfo() {
1566   nsCOMPtr<nsIScreenManager> manager =
1567       do_GetService("@mozilla.org/gfx/screenmanager;1");
1568   MOZ_ASSERT(manager, "failed to get nsIScreenManager");
1569 
1570   nsCOMPtr<nsIScreen> screen;
1571   manager->GetPrimaryScreen(getter_AddRefs(screen));
1572   if (!screen) {
1573     // This can happen in xpcshell, for instance
1574     return;
1575   }
1576 
1577   screen->GetColorDepth(&mScreenDepth);
1578   if (XRE_IsParentProcess()) {
1579     gfxVars::SetScreenDepth(mScreenDepth);
1580   }
1581 
1582   int left, top;
1583   screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height);
1584 }
1585 
SupportsAzureContentForDrawTarget(DrawTarget * aTarget)1586 bool gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget) {
1587   if (!aTarget || !aTarget->IsValid()) {
1588     return false;
1589   }
1590 
1591   return SupportsAzureContentForType(aTarget->GetBackendType());
1592 }
1593 
PurgeSkiaFontCache()1594 void gfxPlatform::PurgeSkiaFontCache() {
1595   if (gfxPlatform::GetPlatform()->GetDefaultContentBackend() ==
1596       BackendType::SKIA) {
1597     SkGraphics::PurgeFontCache();
1598   }
1599 }
1600 
CreateDrawTargetForBackend(BackendType aBackend,const IntSize & aSize,SurfaceFormat aFormat)1601 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForBackend(
1602     BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) {
1603   // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
1604   // create the best offscreen surface for the current system and situation. We
1605   // can easily take advantage of this for the Cairo backend, so that's what we
1606   // do.
1607   // mozilla::gfx::Factory can get away without having all this knowledge for
1608   // now, but this might need to change in the future (using
1609   // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
1610   // backends).
1611   if (aBackend == BackendType::CAIRO) {
1612     RefPtr<gfxASurface> surf =
1613         CreateOffscreenSurface(aSize, SurfaceFormatToImageFormat(aFormat));
1614     if (!surf || surf->CairoStatus()) {
1615       return nullptr;
1616     }
1617     return CreateDrawTargetForSurface(surf, aSize);
1618   }
1619   return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
1620 }
1621 
CreateOffscreenCanvasDrawTarget(const IntSize & aSize,SurfaceFormat aFormat)1622 already_AddRefed<DrawTarget> gfxPlatform::CreateOffscreenCanvasDrawTarget(
1623     const IntSize& aSize, SurfaceFormat aFormat) {
1624   NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
1625 
1626   // If we are using remote canvas we don't want to use acceleration in
1627   // canvas DrawTargets we are not remoting, so we always use the fallback
1628   // software one.
1629   if (!gfxPlatform::UseRemoteCanvas() ||
1630       !gfxPlatform::IsBackendAccelerated(mPreferredCanvasBackend)) {
1631     RefPtr<DrawTarget> target =
1632         CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
1633     if (target || mFallbackCanvasBackend == BackendType::NONE) {
1634       return target.forget();
1635     }
1636   }
1637 
1638 #ifdef XP_WIN
1639   // On Windows, the fallback backend (Cairo) should use its image backend.
1640   return Factory::CreateDrawTarget(mFallbackCanvasBackend, aSize, aFormat);
1641 #else
1642   return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
1643 #endif
1644 }
1645 
CreateOffscreenContentDrawTarget(const IntSize & aSize,SurfaceFormat aFormat,bool aFallback)1646 already_AddRefed<DrawTarget> gfxPlatform::CreateOffscreenContentDrawTarget(
1647     const IntSize& aSize, SurfaceFormat aFormat, bool aFallback) {
1648   BackendType backend = (aFallback) ? mSoftwareBackend : mContentBackend;
1649   NS_ASSERTION(backend != BackendType::NONE, "No backend.");
1650   RefPtr<DrawTarget> dt = CreateDrawTargetForBackend(backend, aSize, aFormat);
1651 
1652   if (!dt) {
1653     return nullptr;
1654   }
1655 
1656   // We'd prefer this to take proper care and return a CaptureDT, but for the
1657   // moment since we can't and this means we're going to be drawing on the main
1658   // thread force it's initialization. See bug 1526045 and bug 1521368.
1659   dt->ClearRect(gfx::Rect());
1660   if (!dt->IsValid()) {
1661     return nullptr;
1662   }
1663   return dt.forget();
1664 }
1665 
CreateSimilarSoftwareDrawTarget(DrawTarget * aDT,const IntSize & aSize,SurfaceFormat aFormat)1666 already_AddRefed<DrawTarget> gfxPlatform::CreateSimilarSoftwareDrawTarget(
1667     DrawTarget* aDT, const IntSize& aSize, SurfaceFormat aFormat) {
1668   RefPtr<DrawTarget> dt;
1669 
1670   if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) {
1671     dt = aDT->CreateSimilarDrawTarget(aSize, aFormat);
1672   } else {
1673     BackendType backendType = BackendType::SKIA;
1674     dt = Factory::CreateDrawTarget(backendType, aSize, aFormat);
1675   }
1676 
1677   return dt.forget();
1678 }
1679 
1680 /* static */
CreateDrawTargetForData(unsigned char * aData,const IntSize & aSize,int32_t aStride,SurfaceFormat aFormat,bool aUninitialized)1681 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForData(
1682     unsigned char* aData, const IntSize& aSize, int32_t aStride,
1683     SurfaceFormat aFormat, bool aUninitialized) {
1684   BackendType backendType = gfxVars::ContentBackend();
1685   NS_ASSERTION(backendType != BackendType::NONE, "No backend.");
1686 
1687   if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) {
1688     backendType = BackendType::SKIA;
1689   }
1690 
1691   RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
1692       backendType, aData, aSize, aStride, aFormat, aUninitialized);
1693 
1694   return dt.forget();
1695 }
1696 
1697 /* static */
BackendTypeForName(const nsCString & aName)1698 BackendType gfxPlatform::BackendTypeForName(const nsCString& aName) {
1699   if (aName.EqualsLiteral("cairo")) return BackendType::CAIRO;
1700   if (aName.EqualsLiteral("skia")) return BackendType::SKIA;
1701   if (aName.EqualsLiteral("direct2d")) return BackendType::DIRECT2D;
1702   if (aName.EqualsLiteral("direct2d1.1")) return BackendType::DIRECT2D1_1;
1703   return BackendType::NONE;
1704 }
1705 
GetFontList(nsAtom * aLangGroup,const nsACString & aGenericFamily,nsTArray<nsString> & aListOfFonts)1706 nsresult gfxPlatform::GetFontList(nsAtom* aLangGroup,
1707                                   const nsACString& aGenericFamily,
1708                                   nsTArray<nsString>& aListOfFonts) {
1709   gfxPlatformFontList::PlatformFontList()->GetFontList(
1710       aLangGroup, aGenericFamily, aListOfFonts);
1711   return NS_OK;
1712 }
1713 
UpdateFontList(bool aFullRebuild)1714 nsresult gfxPlatform::UpdateFontList(bool aFullRebuild) {
1715   gfxPlatformFontList::PlatformFontList()->UpdateFontList(aFullRebuild);
1716   return NS_OK;
1717 }
1718 
GetStandardFamilyName(const nsCString & aFontName,nsACString & aFamilyName)1719 void gfxPlatform::GetStandardFamilyName(const nsCString& aFontName,
1720                                         nsACString& aFamilyName) {
1721   gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName,
1722                                                                  aFamilyName);
1723 }
1724 
GetDefaultFontName(const nsACString & aLangGroup,const nsACString & aGenericFamily)1725 nsAutoCString gfxPlatform::GetDefaultFontName(
1726     const nsACString& aLangGroup, const nsACString& aGenericFamily) {
1727   // To benefit from Return Value Optimization, all paths here must return
1728   // this one variable:
1729   nsAutoCString result;
1730 
1731   auto* pfl = gfxPlatformFontList::PlatformFontList();
1732   FamilyAndGeneric fam = pfl->GetDefaultFontFamily(aLangGroup, aGenericFamily);
1733   if (!pfl->GetLocalizedFamilyName(fam.mFamily, result)) {
1734     NS_WARNING("missing default font-family name");
1735   }
1736 
1737   return result;
1738 }
1739 
DownloadableFontsEnabled()1740 bool gfxPlatform::DownloadableFontsEnabled() {
1741   if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
1742     mAllowDownloadableFonts =
1743         Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
1744   }
1745 
1746   return mAllowDownloadableFonts;
1747 }
1748 
UseCmapsDuringSystemFallback()1749 bool gfxPlatform::UseCmapsDuringSystemFallback() {
1750   if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
1751     mFallbackUsesCmaps =
1752         Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
1753   }
1754 
1755   return mFallbackUsesCmaps;
1756 }
1757 
OpenTypeSVGEnabled()1758 bool gfxPlatform::OpenTypeSVGEnabled() {
1759   if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
1760     mOpenTypeSVGEnabled = Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
1761   }
1762 
1763   return mOpenTypeSVGEnabled > 0;
1764 }
1765 
WordCacheCharLimit()1766 uint32_t gfxPlatform::WordCacheCharLimit() {
1767   if (mWordCacheCharLimit == UNINITIALIZED_VALUE) {
1768     mWordCacheCharLimit =
1769         Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32);
1770     if (mWordCacheCharLimit < 0) {
1771       mWordCacheCharLimit = 32;
1772     }
1773   }
1774 
1775   return uint32_t(mWordCacheCharLimit);
1776 }
1777 
WordCacheMaxEntries()1778 uint32_t gfxPlatform::WordCacheMaxEntries() {
1779   if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) {
1780     mWordCacheMaxEntries =
1781         Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000);
1782     if (mWordCacheMaxEntries < 0) {
1783       mWordCacheMaxEntries = 10000;
1784     }
1785   }
1786 
1787   return uint32_t(mWordCacheMaxEntries);
1788 }
1789 
UseGraphiteShaping()1790 bool gfxPlatform::UseGraphiteShaping() {
1791   if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
1792     mGraphiteShapingEnabled =
1793         Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
1794   }
1795 
1796   return mGraphiteShapingEnabled;
1797 }
1798 
IsFontFormatSupported(uint32_t aFormatFlags)1799 bool gfxPlatform::IsFontFormatSupported(uint32_t aFormatFlags) {
1800   // check for strange format flags
1801   MOZ_ASSERT(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
1802              "strange font format hint set");
1803 
1804   // accept "common" formats that we support on all platforms
1805   if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
1806     return true;
1807   }
1808 
1809   // reject all other formats, known and unknown
1810   if (aFormatFlags != 0) {
1811     return false;
1812   }
1813 
1814   // no format hint set, need to look at data
1815   return true;
1816 }
1817 
CreateFontGroup(nsPresContext * aPresContext,const StyleFontFamilyList & aFontFamilyList,const gfxFontStyle * aStyle,nsAtom * aLanguage,bool aExplicitLanguage,gfxTextPerfMetrics * aTextPerf,gfxUserFontSet * aUserFontSet,gfxFloat aDevToCssSize) const1818 gfxFontGroup* gfxPlatform::CreateFontGroup(
1819     nsPresContext* aPresContext, const StyleFontFamilyList& aFontFamilyList,
1820     const gfxFontStyle* aStyle, nsAtom* aLanguage, bool aExplicitLanguage,
1821     gfxTextPerfMetrics* aTextPerf, gfxUserFontSet* aUserFontSet,
1822     gfxFloat aDevToCssSize) const {
1823   return new gfxFontGroup(aPresContext, aFontFamilyList, aStyle, aLanguage,
1824                           aExplicitLanguage, aTextPerf, aUserFontSet,
1825                           aDevToCssSize);
1826 }
1827 
LookupLocalFont(nsPresContext * aPresContext,const nsACString & aFontName,WeightRange aWeightForEntry,StretchRange aStretchForEntry,SlantStyleRange aStyleForEntry)1828 gfxFontEntry* gfxPlatform::LookupLocalFont(nsPresContext* aPresContext,
1829                                            const nsACString& aFontName,
1830                                            WeightRange aWeightForEntry,
1831                                            StretchRange aStretchForEntry,
1832                                            SlantStyleRange aStyleForEntry) {
1833   return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(
1834       aPresContext, aFontName, aWeightForEntry, aStretchForEntry,
1835       aStyleForEntry);
1836 }
1837 
MakePlatformFont(const nsACString & aFontName,WeightRange aWeightForEntry,StretchRange aStretchForEntry,SlantStyleRange aStyleForEntry,const uint8_t * aFontData,uint32_t aLength)1838 gfxFontEntry* gfxPlatform::MakePlatformFont(const nsACString& aFontName,
1839                                             WeightRange aWeightForEntry,
1840                                             StretchRange aStretchForEntry,
1841                                             SlantStyleRange aStyleForEntry,
1842                                             const uint8_t* aFontData,
1843                                             uint32_t aLength) {
1844   return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(
1845       aFontName, aWeightForEntry, aStretchForEntry, aStyleForEntry, aFontData,
1846       aLength);
1847 }
1848 
GetBackendPrefs() const1849 BackendPrefsData gfxPlatform::GetBackendPrefs() const {
1850   BackendPrefsData data;
1851 
1852   data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
1853   data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
1854 
1855 #ifdef MOZ_WIDGET_GTK
1856   data.mCanvasBitmask |= BackendTypeBit(BackendType::CAIRO);
1857   data.mContentBitmask |= BackendTypeBit(BackendType::CAIRO);
1858 #endif
1859 
1860   data.mCanvasDefault = BackendType::SKIA;
1861   data.mContentDefault = BackendType::SKIA;
1862 
1863   return data;
1864 }
1865 
InitBackendPrefs(BackendPrefsData && aPrefsData)1866 void gfxPlatform::InitBackendPrefs(BackendPrefsData&& aPrefsData) {
1867   mPreferredCanvasBackend = GetCanvasBackendPref(aPrefsData.mCanvasBitmask);
1868   if (mPreferredCanvasBackend == BackendType::NONE) {
1869     mPreferredCanvasBackend = aPrefsData.mCanvasDefault;
1870   }
1871 
1872   if (mPreferredCanvasBackend == BackendType::DIRECT2D1_1) {
1873     // Falling back to D2D 1.0 won't help us here. When D2D 1.1 DT creation
1874     // fails it means the surface was too big or there's something wrong with
1875     // the device. D2D 1.0 will encounter a similar situation.
1876     mFallbackCanvasBackend = GetCanvasBackendPref(
1877         aPrefsData.mCanvasBitmask & ~(BackendTypeBit(mPreferredCanvasBackend) |
1878                                       BackendTypeBit(BackendType::DIRECT2D)));
1879   } else {
1880     mFallbackCanvasBackend = GetCanvasBackendPref(
1881         aPrefsData.mCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
1882   }
1883 
1884   mContentBackendBitmask = aPrefsData.mContentBitmask;
1885   mContentBackend = GetContentBackendPref(mContentBackendBitmask);
1886   if (mContentBackend == BackendType::NONE) {
1887     mContentBackend = aPrefsData.mContentDefault;
1888     // mContentBackendBitmask is our canonical reference for supported
1889     // backends so we need to add the default if we are using it and
1890     // overriding the prefs.
1891     mContentBackendBitmask |= BackendTypeBit(aPrefsData.mContentDefault);
1892   }
1893 
1894   uint32_t swBackendBits = BackendTypeBit(BackendType::SKIA);
1895 #ifdef MOZ_WIDGET_GTK
1896   swBackendBits |= BackendTypeBit(BackendType::CAIRO);
1897 #endif
1898   mSoftwareBackend = GetContentBackendPref(swBackendBits);
1899   if (mSoftwareBackend == BackendType::NONE) {
1900     mSoftwareBackend = BackendType::SKIA;
1901   }
1902 
1903   // If we don't have a fallback canvas backend then use the same software
1904   // fallback as content.
1905   if (mFallbackCanvasBackend == BackendType::NONE) {
1906     mFallbackCanvasBackend = mSoftwareBackend;
1907   }
1908 
1909   if (XRE_IsParentProcess()) {
1910     gfxVars::SetContentBackend(mContentBackend);
1911     gfxVars::SetSoftwareBackend(mSoftwareBackend);
1912   }
1913 }
1914 
1915 /* static */
GetCanvasBackendPref(uint32_t aBackendBitmask)1916 BackendType gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask) {
1917   return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
1918 }
1919 
1920 /* static */
GetContentBackendPref(uint32_t & aBackendBitmask)1921 BackendType gfxPlatform::GetContentBackendPref(uint32_t& aBackendBitmask) {
1922   return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
1923 }
1924 
1925 /* static */
GetBackendPref(const char * aBackendPrefName,uint32_t & aBackendBitmask)1926 BackendType gfxPlatform::GetBackendPref(const char* aBackendPrefName,
1927                                         uint32_t& aBackendBitmask) {
1928   nsTArray<nsCString> backendList;
1929   nsAutoCString prefString;
1930   if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, prefString))) {
1931     ParseString(prefString, ',', backendList);
1932   }
1933 
1934   uint32_t allowedBackends = 0;
1935   BackendType result = BackendType::NONE;
1936   for (uint32_t i = 0; i < backendList.Length(); ++i) {
1937     BackendType type = BackendTypeForName(backendList[i]);
1938     if (BackendTypeBit(type) & aBackendBitmask) {
1939       allowedBackends |= BackendTypeBit(type);
1940       if (result == BackendType::NONE) {
1941         result = type;
1942       }
1943     }
1944   }
1945 
1946   aBackendBitmask = allowedBackends;
1947   return result;
1948 }
1949 
InSafeMode()1950 bool gfxPlatform::InSafeMode() {
1951   static bool sSafeModeInitialized = false;
1952   static bool sInSafeMode = false;
1953 
1954   if (!sSafeModeInitialized) {
1955     sSafeModeInitialized = true;
1956     nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
1957     if (xr) {
1958       xr->GetInSafeMode(&sInSafeMode);
1959     }
1960   }
1961   return sInSafeMode;
1962 }
1963 
OffMainThreadCompositingEnabled()1964 bool gfxPlatform::OffMainThreadCompositingEnabled() {
1965   return UsesOffMainThreadCompositing();
1966 }
1967 
SetCMSModeOverride(CMSMode aMode)1968 void gfxPlatform::SetCMSModeOverride(CMSMode aMode) {
1969   MOZ_ASSERT(gCMSInitialized);
1970   gCMSMode = aMode;
1971 }
1972 
GetRenderingIntent()1973 int gfxPlatform::GetRenderingIntent() {
1974   // StaticPrefList.yaml is using 0 as the default for the rendering
1975   // intent preference, based on that being the value for
1976   // QCMS_INTENT_DEFAULT.  Assert here to catch if that ever
1977   // changes and we can then figure out what to do about it.
1978   MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
1979 
1980   /* Try to query the pref system for a rendering intent. */
1981   int32_t pIntent = StaticPrefs::gfx_color_management_rendering_intent();
1982   if ((pIntent < QCMS_INTENT_MIN) || (pIntent > QCMS_INTENT_MAX)) {
1983     /* If the pref is out of range, use embedded profile. */
1984     pIntent = -1;
1985   }
1986   return pIntent;
1987 }
1988 
TransformPixel(const sRGBColor & in,qcms_transform * transform)1989 DeviceColor gfxPlatform::TransformPixel(const sRGBColor& in,
1990                                         qcms_transform* transform) {
1991   if (transform) {
1992     /* we want the bytes in RGB order */
1993 #ifdef IS_LITTLE_ENDIAN
1994     /* ABGR puts the bytes in |RGBA| order on little endian */
1995     uint32_t packed = in.ToABGR();
1996     qcms_transform_data(transform, (uint8_t*)&packed, (uint8_t*)&packed, 1);
1997     auto out = DeviceColor::FromABGR(packed);
1998 #else
1999     /* ARGB puts the bytes in |ARGB| order on big endian */
2000     uint32_t packed = in.UnusualToARGB();
2001     /* add one to move past the alpha byte */
2002     qcms_transform_data(transform, (uint8_t*)&packed + 1, (uint8_t*)&packed + 1,
2003                         1);
2004     auto out = DeviceColor::UnusualFromARGB(packed);
2005 #endif
2006     out.a = in.a;
2007     return out;
2008   }
2009   return DeviceColor(in.r, in.g, in.b, in.a);
2010 }
2011 
GetPlatformCMSOutputProfileData()2012 nsTArray<uint8_t> gfxPlatform::GetPlatformCMSOutputProfileData() {
2013   return GetPrefCMSOutputProfileData();
2014 }
2015 
GetPrefCMSOutputProfileData()2016 nsTArray<uint8_t> gfxPlatform::GetPrefCMSOutputProfileData() {
2017   nsAutoCString fname;
2018   Preferences::GetCString("gfx.color_management.display_profile", fname);
2019 
2020   if (fname.IsEmpty()) {
2021     return nsTArray<uint8_t>();
2022   }
2023 
2024   void* mem = nullptr;
2025   size_t size = 0;
2026   qcms_data_from_path(fname.get(), &mem, &size);
2027 
2028   nsTArray<uint8_t> result;
2029 
2030   if (mem) {
2031     result.AppendElements(static_cast<uint8_t*>(mem), size);
2032     free(mem);
2033   }
2034 
2035   return result;
2036 }
2037 
GetInitContentDeviceData()2038 const mozilla::gfx::ContentDeviceData* gfxPlatform::GetInitContentDeviceData() {
2039   return gContentDeviceInitData;
2040 }
2041 
InitializeCMS()2042 void gfxPlatform::InitializeCMS() {
2043   if (gCMSInitialized) {
2044     return;
2045   }
2046 
2047   if (XRE_IsGPUProcess()) {
2048     // Colors in the GPU process should already be managed, so we don't need to
2049     // perform color management there.
2050     gCMSInitialized = true;
2051     return;
2052   }
2053 
2054   MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
2055                         "CMS should be initialized on the main thread");
2056   if (MOZ_UNLIKELY(!NS_IsMainThread())) {
2057     return;
2058   }
2059 
2060   {
2061     int32_t mode = StaticPrefs::gfx_color_management_mode();
2062     if (mode >= 0 && mode < int32_t(CMSMode::AllCount)) {
2063       gCMSMode = CMSMode(mode);
2064     }
2065   }
2066 
2067   gCMSsRGBProfile = qcms_profile_sRGB();
2068 
2069   /* Determine if we're using the internal override to force sRGB as
2070      an output profile for reftests. See Bug 452125.
2071 
2072      Note that we don't normally (outside of tests) set a default value
2073      of this preference, which means nsIPrefBranch::GetBoolPref will
2074      typically throw (and leave its out-param untouched).
2075    */
2076   if (StaticPrefs::gfx_color_management_force_srgb() ||
2077       StaticPrefs::gfx_color_management_native_srgb()) {
2078     gCMSOutputProfile = gCMSsRGBProfile;
2079   }
2080 
2081   if (!gCMSOutputProfile) {
2082     nsTArray<uint8_t> outputProfileData =
2083         gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfileData();
2084     if (!outputProfileData.IsEmpty()) {
2085       gCMSOutputProfile = qcms_profile_from_memory(outputProfileData.Elements(),
2086                                                    outputProfileData.Length());
2087     }
2088   }
2089 
2090   /* Determine if the profile looks bogus. If so, close the profile
2091    * and use sRGB instead. See bug 460629, */
2092   if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
2093     NS_ASSERTION(gCMSOutputProfile != gCMSsRGBProfile,
2094                  "Builtin sRGB profile tagged as bogus!!!");
2095     qcms_profile_release(gCMSOutputProfile);
2096     gCMSOutputProfile = nullptr;
2097   }
2098 
2099   if (!gCMSOutputProfile) {
2100     gCMSOutputProfile = gCMSsRGBProfile;
2101   }
2102 
2103   /* Precache the LUT16 Interpolations for the output profile. See
2104      bug 444661 for details. */
2105   qcms_profile_precache_output_transform(gCMSOutputProfile);
2106 
2107   // Create the RGB transform.
2108   gCMSRGBTransform =
2109       qcms_transform_create(gCMSsRGBProfile, QCMS_DATA_RGB_8, gCMSOutputProfile,
2110                             QCMS_DATA_RGB_8, QCMS_INTENT_PERCEPTUAL);
2111 
2112   // And the inverse.
2113   gCMSInverseRGBTransform =
2114       qcms_transform_create(gCMSOutputProfile, QCMS_DATA_RGB_8, gCMSsRGBProfile,
2115                             QCMS_DATA_RGB_8, QCMS_INTENT_PERCEPTUAL);
2116 
2117   // The RGBA transform.
2118   gCMSRGBATransform = qcms_transform_create(gCMSsRGBProfile, QCMS_DATA_RGBA_8,
2119                                             gCMSOutputProfile, QCMS_DATA_RGBA_8,
2120                                             QCMS_INTENT_PERCEPTUAL);
2121 
2122   // And the BGRA one.
2123   gCMSBGRATransform = qcms_transform_create(gCMSsRGBProfile, QCMS_DATA_BGRA_8,
2124                                             gCMSOutputProfile, QCMS_DATA_BGRA_8,
2125                                             QCMS_INTENT_PERCEPTUAL);
2126 
2127   // FIXME: We only enable iccv4 after we create the platform profile, to
2128   // wallpaper over bug 1697787.
2129   //
2130   // This should happen ideally right after setting gCMSMode.
2131   if (StaticPrefs::gfx_color_management_enablev4()) {
2132     qcms_enable_iccv4();
2133   }
2134 
2135   gCMSInitialized = true;
2136 }
2137 
GetCMSOSRGBATransform()2138 qcms_transform* gfxPlatform::GetCMSOSRGBATransform() {
2139   switch (SurfaceFormat::OS_RGBA) {
2140     case SurfaceFormat::B8G8R8A8:
2141       return GetCMSBGRATransform();
2142     case SurfaceFormat::R8G8B8A8:
2143       return GetCMSRGBATransform();
2144     default:
2145       // We do not support color management with big endian.
2146       return nullptr;
2147   }
2148 }
2149 
GetCMSOSRGBAType()2150 qcms_data_type gfxPlatform::GetCMSOSRGBAType() {
2151   switch (SurfaceFormat::OS_RGBA) {
2152     case SurfaceFormat::B8G8R8A8:
2153       return QCMS_DATA_BGRA_8;
2154     case SurfaceFormat::R8G8B8A8:
2155       return QCMS_DATA_RGBA_8;
2156     default:
2157       // We do not support color management with big endian.
2158       return QCMS_DATA_RGBA_8;
2159   }
2160 }
2161 
2162 /* Shuts down various transforms and profiles for CMS. */
ShutdownCMS()2163 void gfxPlatform::ShutdownCMS() {
2164   if (gCMSRGBTransform) {
2165     qcms_transform_release(gCMSRGBTransform);
2166     gCMSRGBTransform = nullptr;
2167   }
2168   if (gCMSInverseRGBTransform) {
2169     qcms_transform_release(gCMSInverseRGBTransform);
2170     gCMSInverseRGBTransform = nullptr;
2171   }
2172   if (gCMSRGBATransform) {
2173     qcms_transform_release(gCMSRGBATransform);
2174     gCMSRGBATransform = nullptr;
2175   }
2176   if (gCMSBGRATransform) {
2177     qcms_transform_release(gCMSBGRATransform);
2178     gCMSBGRATransform = nullptr;
2179   }
2180   if (gCMSOutputProfile) {
2181     qcms_profile_release(gCMSOutputProfile);
2182 
2183     // handle the aliased case
2184     if (gCMSsRGBProfile == gCMSOutputProfile) {
2185       gCMSsRGBProfile = nullptr;
2186     }
2187     gCMSOutputProfile = nullptr;
2188   }
2189   if (gCMSsRGBProfile) {
2190     qcms_profile_release(gCMSsRGBProfile);
2191     gCMSsRGBProfile = nullptr;
2192   }
2193 
2194   // Reset the state variables
2195   gCMSMode = CMSMode::Off;
2196   gCMSInitialized = false;
2197 }
2198 
GetBidiNumeralOption()2199 int32_t gfxPlatform::GetBidiNumeralOption() {
2200   if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
2201     mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
2202   }
2203   return mBidiNumeralOption;
2204 }
2205 
2206 /* static */
FlushFontAndWordCaches()2207 void gfxPlatform::FlushFontAndWordCaches() {
2208   gfxFontCache* fontCache = gfxFontCache::GetCache();
2209   if (fontCache) {
2210     fontCache->Flush();
2211   }
2212 
2213   gfxPlatform::PurgeSkiaFontCache();
2214 }
2215 
2216 /* static */
ForceGlobalReflow(NeedsReframe aNeedsReframe,BroadcastToChildren aBroadcastToChildren)2217 void gfxPlatform::ForceGlobalReflow(NeedsReframe aNeedsReframe,
2218                                     BroadcastToChildren aBroadcastToChildren) {
2219   MOZ_ASSERT(NS_IsMainThread());
2220   const bool reframe = aNeedsReframe == NeedsReframe::Yes;
2221   // Send a notification that will be observed by PresShells in this process
2222   // only.
2223   if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
2224     char16_t needsReframe[] = {char16_t(reframe), 0};
2225     obs->NotifyObservers(nullptr, "font-info-updated", needsReframe);
2226   }
2227   if (XRE_IsParentProcess() &&
2228       aBroadcastToChildren == BroadcastToChildren::Yes) {
2229     // Propagate the change to child processes.
2230     for (auto* process :
2231          dom::ContentParent::AllProcesses(dom::ContentParent::eLive)) {
2232       Unused << process->SendForceGlobalReflow(reframe);
2233     }
2234   }
2235 }
2236 
FontsPrefsChanged(const char * aPref)2237 void gfxPlatform::FontsPrefsChanged(const char* aPref) {
2238   NS_ASSERTION(aPref != nullptr, "null preference");
2239   if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
2240     mAllowDownloadableFonts = UNINITIALIZED_VALUE;
2241   } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
2242     mFallbackUsesCmaps = UNINITIALIZED_VALUE;
2243   } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) {
2244     mWordCacheCharLimit = UNINITIALIZED_VALUE;
2245     FlushFontAndWordCaches();
2246   } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) {
2247     mWordCacheMaxEntries = UNINITIALIZED_VALUE;
2248     FlushFontAndWordCaches();
2249   } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
2250     mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
2251     FlushFontAndWordCaches();
2252   } else if (
2253 #if defined(XP_MACOSX)
2254       !strcmp(GFX_PREF_CORETEXT_SHAPING, aPref) ||
2255 #endif
2256       !strcmp("gfx.font_rendering.ahem_antialias_none", aPref)) {
2257     FlushFontAndWordCaches();
2258   } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
2259     mBidiNumeralOption = UNINITIALIZED_VALUE;
2260   } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
2261     mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
2262     gfxFontCache::GetCache()->AgeAllGenerations();
2263     gfxFontCache::GetCache()->NotifyGlyphsChanged();
2264   }
2265 }
2266 
GetLog(eGfxLog aWhichLog)2267 mozilla::LogModule* gfxPlatform::GetLog(eGfxLog aWhichLog) {
2268   // logs shared across gfx
2269   static LazyLogModule sFontlistLog("fontlist");
2270   static LazyLogModule sFontInitLog("fontinit");
2271   static LazyLogModule sTextrunLog("textrun");
2272   static LazyLogModule sTextrunuiLog("textrunui");
2273   static LazyLogModule sCmapDataLog("cmapdata");
2274   static LazyLogModule sTextPerfLog("textperf");
2275 
2276   switch (aWhichLog) {
2277     case eGfxLog_fontlist:
2278       return sFontlistLog;
2279     case eGfxLog_fontinit:
2280       return sFontInitLog;
2281     case eGfxLog_textrun:
2282       return sTextrunLog;
2283     case eGfxLog_textrunui:
2284       return sTextrunuiLog;
2285     case eGfxLog_cmapdata:
2286       return sCmapDataLog;
2287     case eGfxLog_textperf:
2288       return sTextPerfLog;
2289   }
2290 
2291   MOZ_ASSERT_UNREACHABLE("Unexpected log type");
2292   return nullptr;
2293 }
2294 
ScreenReferenceDrawTarget()2295 RefPtr<mozilla::gfx::DrawTarget> gfxPlatform::ScreenReferenceDrawTarget() {
2296   return (mScreenReferenceDrawTarget)
2297              ? mScreenReferenceDrawTarget
2298              : gPlatform->CreateOffscreenContentDrawTarget(
2299                    IntSize(1, 1), SurfaceFormat::B8G8R8A8, true);
2300 }
2301 
Optimal2DFormatForContent(gfxContentType aContent)2302 mozilla::gfx::SurfaceFormat gfxPlatform::Optimal2DFormatForContent(
2303     gfxContentType aContent) {
2304   switch (aContent) {
2305     case gfxContentType::COLOR:
2306       switch (GetOffscreenFormat()) {
2307         case SurfaceFormat::A8R8G8B8_UINT32:
2308           return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2309         case SurfaceFormat::X8R8G8B8_UINT32:
2310           return mozilla::gfx::SurfaceFormat::B8G8R8X8;
2311         case SurfaceFormat::R5G6B5_UINT16:
2312           return mozilla::gfx::SurfaceFormat::R5G6B5_UINT16;
2313         default:
2314           MOZ_ASSERT_UNREACHABLE(
2315               "unknown gfxImageFormat for "
2316               "gfxContentType::COLOR");
2317           return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2318       }
2319     case gfxContentType::ALPHA:
2320       return mozilla::gfx::SurfaceFormat::A8;
2321     case gfxContentType::COLOR_ALPHA:
2322       return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2323     default:
2324       MOZ_ASSERT_UNREACHABLE("unknown gfxContentType");
2325       return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2326   }
2327 }
2328 
OptimalFormatForContent(gfxContentType aContent)2329 gfxImageFormat gfxPlatform::OptimalFormatForContent(gfxContentType aContent) {
2330   switch (aContent) {
2331     case gfxContentType::COLOR:
2332       return GetOffscreenFormat();
2333     case gfxContentType::ALPHA:
2334       return SurfaceFormat::A8;
2335     case gfxContentType::COLOR_ALPHA:
2336       return SurfaceFormat::A8R8G8B8_UINT32;
2337     default:
2338       MOZ_ASSERT_UNREACHABLE("unknown gfxContentType");
2339       return SurfaceFormat::A8R8G8B8_UINT32;
2340   }
2341 }
2342 
2343 /**
2344  * There are a number of layers acceleration (or layers in general) preferences
2345  * that should be consistent for the lifetime of the application (bug 840967).
2346  * As such, we will evaluate them all as soon as one of them is evaluated
2347  * and remember the values.  Changing these preferences during the run will
2348  * not have any effect until we restart.
2349  */
2350 static mozilla::Atomic<bool> sLayersSupportsHardwareVideoDecoding(false);
2351 static bool sLayersHardwareVideoDecodingFailed = false;
2352 
2353 static mozilla::Atomic<bool> sLayersAccelerationPrefsInitialized(false);
2354 
VideoDecodingFailedChangedCallback(const char * aPref,void *)2355 static void VideoDecodingFailedChangedCallback(const char* aPref, void*) {
2356   sLayersHardwareVideoDecodingFailed = Preferences::GetBool(aPref, false);
2357   gfxPlatform::GetPlatform()->UpdateCanUseHardwareVideoDecoding();
2358 }
2359 
UpdateCanUseHardwareVideoDecoding()2360 void gfxPlatform::UpdateCanUseHardwareVideoDecoding() {
2361   if (XRE_IsParentProcess()) {
2362     gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding());
2363   }
2364 }
2365 
UpdateForceSubpixelAAWherePossible()2366 void gfxPlatform::UpdateForceSubpixelAAWherePossible() {
2367   bool forceSubpixelAAWherePossible =
2368       StaticPrefs::gfx_webrender_quality_force_subpixel_aa_where_possible();
2369   gfxVars::SetForceSubpixelAAWherePossible(forceSubpixelAAWherePossible);
2370 }
2371 
InitAcceleration()2372 void gfxPlatform::InitAcceleration() {
2373   if (sLayersAccelerationPrefsInitialized) {
2374     return;
2375   }
2376 
2377   InitCompositorAccelerationPrefs();
2378 
2379   // If this is called for the first time on a non-main thread, we're screwed.
2380   // At the moment there's no explicit guarantee that the main thread calls
2381   // this before the compositor thread, but let's at least make the assumption
2382   // explicit.
2383   MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
2384 
2385   nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
2386   nsCString discardFailureId;
2387   int32_t status;
2388 
2389   if (XRE_IsParentProcess()) {
2390     gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
2391     gfxVars::SetOffscreenFormat(GetOffscreenFormat());
2392     gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL(
2393         RequiresAcceleratedGLContextForCompositorOGL());
2394 #ifdef XP_WIN
2395     if (NS_SUCCEEDED(
2396             gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX,
2397                                       discardFailureId, &status))) {
2398       gfxVars::SetAllowD3D11KeyedMutex(status == nsIGfxInfo::FEATURE_STATUS_OK);
2399     } else {
2400       // If we couldn't properly evaluate the status, err on the side
2401       // of caution and give this functionality to the user.
2402       gfxCriticalNote << "Cannot evaluate keyed mutex feature status";
2403       gfxVars::SetAllowD3D11KeyedMutex(true);
2404     }
2405     if (StaticPrefs::gfx_direct3d11_use_double_buffering() &&
2406         IsWin10OrLater()) {
2407       gfxVars::SetUseDoubleBufferingWithCompositor(true);
2408     }
2409 #endif
2410   }
2411 
2412   if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) &&
2413 #ifdef XP_WIN
2414       Preferences::GetBool("media.wmf.dxva.enabled", true) &&
2415 #endif
2416       NS_SUCCEEDED(
2417           gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING,
2418                                     discardFailureId, &status))) {
2419     if (status == nsIGfxInfo::FEATURE_STATUS_OK ||
2420         StaticPrefs::media_hardware_video_decoding_force_enabled_AtStartup()) {
2421       sLayersSupportsHardwareVideoDecoding = true;
2422     }
2423   }
2424 
2425   sLayersAccelerationPrefsInitialized = true;
2426 
2427   if (XRE_IsParentProcess()) {
2428     Preferences::RegisterCallbackAndCall(
2429         VideoDecodingFailedChangedCallback,
2430         "media.hardware-video-decoding.failed");
2431     InitGPUProcessPrefs();
2432 
2433     gfxVars::SetRemoteCanvasEnabled(StaticPrefs::gfx_canvas_remote() &&
2434                                     gfxConfig::IsEnabled(Feature::GPU_PROCESS));
2435   }
2436 }
2437 
InitGPUProcessPrefs()2438 void gfxPlatform::InitGPUProcessPrefs() {
2439   // We want to hide this from about:support, so only set a default if the
2440   // pref is known to be true.
2441   if (!StaticPrefs::layers_gpu_process_enabled_AtStartup() &&
2442       !StaticPrefs::layers_gpu_process_force_enabled_AtStartup()) {
2443     return;
2444   }
2445 
2446   FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
2447 
2448   nsCString message;
2449   nsCString failureId;
2450   if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_GPU_PROCESS,
2451                                         &message, failureId)) {
2452     gpuProc.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
2453     // Don't return early here. We must continue the checks below in case
2454     // the user has force-enabled the GPU process.
2455   }
2456 
2457   // We require E10S - otherwise, there is very little benefit to the GPU
2458   // process, since the UI process must still use acceleration for
2459   // performance.
2460   if (!BrowserTabsRemoteAutostart()) {
2461     gpuProc.DisableByDefault(FeatureStatus::Unavailable,
2462                              "Multi-process mode is not enabled",
2463                              "FEATURE_FAILURE_NO_E10S"_ns);
2464   } else {
2465     gpuProc.SetDefaultFromPref(
2466         StaticPrefs::GetPrefName_layers_gpu_process_enabled(), true,
2467         StaticPrefs::GetPrefDefault_layers_gpu_process_enabled());
2468   }
2469 
2470   if (StaticPrefs::layers_gpu_process_force_enabled_AtStartup()) {
2471     gpuProc.UserForceEnable("User force-enabled via pref");
2472   }
2473 
2474   if (IsHeadless()) {
2475     gpuProc.ForceDisable(FeatureStatus::Blocked, "Headless mode is enabled",
2476                          "FEATURE_FAILURE_HEADLESS_MODE"_ns);
2477     return;
2478   }
2479   if (InSafeMode()) {
2480     gpuProc.ForceDisable(FeatureStatus::Blocked, "Safe-mode is enabled",
2481                          "FEATURE_FAILURE_SAFE_MODE"_ns);
2482     return;
2483   }
2484 
2485   InitPlatformGPUProcessPrefs();
2486 }
2487 
InitCompositorAccelerationPrefs()2488 void gfxPlatform::InitCompositorAccelerationPrefs() {
2489   const char* acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
2490 
2491   FeatureState& feature = gfxConfig::GetFeature(Feature::HW_COMPOSITING);
2492 
2493   // Base value - does the platform allow acceleration?
2494   if (feature.SetDefault(AccelerateLayersByDefault(), FeatureStatus::Blocked,
2495                          "Acceleration blocked by platform")) {
2496     if (StaticPrefs::
2497             layers_acceleration_disabled_AtStartup_DoNotUseDirectly()) {
2498       feature.UserDisable("Disabled by layers.acceleration.disabled=true",
2499                           "FEATURE_FAILURE_COMP_PREF"_ns);
2500     } else if (acceleratedEnv && *acceleratedEnv == '0') {
2501       feature.UserDisable("Disabled by envvar", "FEATURE_FAILURE_COMP_ENV"_ns);
2502     }
2503   } else {
2504     if (acceleratedEnv && *acceleratedEnv == '1') {
2505       feature.UserEnable("Enabled by envvar");
2506     }
2507   }
2508 
2509   // This has specific meaning elsewhere, so we always record it.
2510   if (StaticPrefs::
2511           layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly()) {
2512     feature.UserForceEnable("Force-enabled by pref");
2513   }
2514 
2515   // Safe, headless, and record/replay modes override everything.
2516   if (InSafeMode()) {
2517     feature.ForceDisable(FeatureStatus::Blocked,
2518                          "Acceleration blocked by safe-mode",
2519                          "FEATURE_FAILURE_COMP_SAFEMODE"_ns);
2520   }
2521   if (IsHeadless()) {
2522     feature.ForceDisable(FeatureStatus::Blocked,
2523                          "Acceleration blocked by headless mode",
2524                          "FEATURE_FAILURE_COMP_HEADLESSMODE"_ns);
2525   }
2526 }
2527 
2528 /*static*/
WebRenderPrefEnabled()2529 bool gfxPlatform::WebRenderPrefEnabled() {
2530   return StaticPrefs::gfx_webrender_all_AtStartup() ||
2531          StaticPrefs::gfx_webrender_enabled_AtStartup_DoNotUseDirectly();
2532 }
2533 
2534 /*static*/
WebRenderEnvvarEnabled()2535 bool gfxPlatform::WebRenderEnvvarEnabled() {
2536   const char* env = PR_GetEnv("MOZ_WEBRENDER");
2537   return (env && *env == '1');
2538 }
2539 
WebRenderResourcePathOverride()2540 /* static */ const char* gfxPlatform::WebRenderResourcePathOverride() {
2541   const char* resourcePath = PR_GetEnv("WR_RESOURCE_PATH");
2542   if (!resourcePath || resourcePath[0] == '\0') {
2543     return nullptr;
2544   }
2545   return resourcePath;
2546 }
2547 
InitWebRenderConfig()2548 void gfxPlatform::InitWebRenderConfig() {
2549   bool prefEnabled = WebRenderPrefEnabled();
2550   bool envvarEnabled = WebRenderEnvvarEnabled();
2551 
2552   // WR? WR+   => means WR was enabled via gfx.webrender.all.qualified on
2553   //              qualified hardware
2554   // WR! WR+   => means WR was enabled via gfx.webrender.{all,enabled} or
2555   //              envvar, possibly on unqualified hardware
2556   // In all cases WR- means WR was not enabled, for one of many possible
2557   // reasons. Prior to bug 1523788 landing the gfx.webrender.{all,enabled}
2558   // prefs only worked on Nightly so keep that in mind when looking at older
2559   // crash reports.
2560   ScopedGfxFeatureReporter reporter("WR", prefEnabled || envvarEnabled);
2561   if (!XRE_IsParentProcess()) {
2562     // The parent process runs through all the real decision-making code
2563     // later in this function. For other processes we still want to report
2564     // the state of the feature for crash reports.
2565     if (gfxVars::UseWebRender()) {
2566       reporter.SetSuccessful();
2567     }
2568     return;
2569   }
2570 
2571   // Update the gfxConfig feature states.
2572   gfxConfigManager manager;
2573   manager.Init();
2574   manager.ConfigureWebRender();
2575 
2576   bool hasHardware = gfxConfig::IsEnabled(Feature::WEBRENDER);
2577   bool hasSoftware = gfxConfig::IsEnabled(Feature::WEBRENDER_SOFTWARE);
2578   bool hasWebRender = hasHardware || hasSoftware;
2579 
2580 #ifdef MOZ_WIDGET_GTK
2581   // We require a hardware driver to back the GL context unless the user forced
2582   // on WebRender.
2583   if (!gfxConfig::IsForcedOnByUser(Feature::WEBRENDER) &&
2584       StaticPrefs::gfx_webrender_reject_software_driver_AtStartup()) {
2585     gfxVars::SetWebRenderRequiresHardwareDriver(true);
2586   }
2587 #endif
2588 
2589 #ifdef XP_WIN
2590   if (gfxConfig::IsEnabled(Feature::WEBRENDER_ANGLE)) {
2591     gfxVars::SetUseWebRenderANGLE(hasWebRender);
2592   }
2593 #endif
2594 
2595   if (gfxConfig::IsEnabled(Feature::WEBRENDER_SHADER_CACHE)) {
2596     gfxVars::SetUseWebRenderProgramBinaryDisk(hasWebRender);
2597   }
2598 
2599   gfxVars::SetUseWebRenderOptimizedShaders(
2600       gfxConfig::IsEnabled(Feature::WEBRENDER_OPTIMIZED_SHADERS));
2601 
2602   gfxVars::SetUseSoftwareWebRender(!hasHardware && hasSoftware);
2603 
2604   Preferences::RegisterPrefixCallbackAndCall(SwapIntervalPrefChangeCallback,
2605                                              "gfx.swap-interval");
2606 
2607   // gfxFeature is not usable in the GPU process, so we use gfxVars to transmit
2608   // this feature
2609   if (hasWebRender) {
2610     gfxVars::SetUseWebRender(true);
2611     reporter.SetSuccessful();
2612 
2613     Preferences::RegisterPrefixCallbackAndCall(WebRenderDebugPrefChangeCallback,
2614                                                WR_DEBUG_PREF);
2615 
2616     RegisterWebRenderBoolParamCallback();
2617 
2618     Preferences::RegisterPrefixCallbackAndCall(
2619         WebRendeProfilerUIPrefChangeCallback,
2620         "gfx.webrender.debug.profiler-ui");
2621     Preferences::RegisterCallback(
2622         WebRenderQualityPrefChangeCallback,
2623         nsDependentCString(
2624             StaticPrefs::
2625                 GetPrefName_gfx_webrender_quality_force_subpixel_aa_where_possible()));
2626 
2627     Preferences::RegisterCallback(
2628         WebRenderBatchingPrefChangeCallback,
2629         nsDependentCString(
2630             StaticPrefs::GetPrefName_gfx_webrender_batching_lookback()));
2631 
2632     Preferences::RegisterCallbackAndCall(
2633         WebRenderBlobTileSizePrefChangeCallback,
2634         nsDependentCString(
2635             StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size()));
2636 
2637     Preferences::RegisterCallbackAndCall(
2638         WebRenderUploadThresholdPrefChangeCallback,
2639         nsDependentCString(
2640             StaticPrefs::GetPrefName_gfx_webrender_batched_upload_threshold()));
2641 
2642     if (WebRenderResourcePathOverride()) {
2643       CrashReporter::AnnotateCrashReport(
2644           CrashReporter::Annotation::IsWebRenderResourcePathOverridden, true);
2645     }
2646 
2647     UpdateForceSubpixelAAWherePossible();
2648   }
2649 
2650 #ifdef XP_WIN
2651   if (gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT)) {
2652     gfxVars::SetUseWebRenderDCompWin(true);
2653   }
2654   if (StaticPrefs::gfx_webrender_software_d3d11_AtStartup()) {
2655     gfxVars::SetAllowSoftwareWebRenderD3D11(true);
2656   }
2657   if (StaticPrefs::gfx_webrender_dcomp_video_overlay_win_AtStartup()) {
2658     if (IsWin10AnniversaryUpdateOrLater() &&
2659         gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) {
2660       MOZ_ASSERT(gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT));
2661       gfxVars::SetUseWebRenderDCompVideoOverlayWin(true);
2662     }
2663   }
2664   if (Preferences::GetBool("gfx.webrender.flip-sequential", false)) {
2665     if (UseWebRender() && gfxVars::UseWebRenderANGLE()) {
2666       gfxVars::SetUseWebRenderFlipSequentialWin(true);
2667     }
2668   }
2669   if (Preferences::GetBool("gfx.webrender.triple-buffering.enabled", false)) {
2670     if (gfxVars::UseWebRenderDCompWin() ||
2671         gfxVars::UseWebRenderFlipSequentialWin()) {
2672       gfxVars::SetUseWebRenderTripleBufferingWin(true);
2673     }
2674   }
2675 #endif
2676 
2677   if (gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) {
2678     gfxVars::SetUseWebRenderCompositor(true);
2679   }
2680 
2681   Telemetry::ScalarSet(
2682       Telemetry::ScalarID::GFX_OS_COMPOSITOR,
2683       gfx::gfxConfig::IsEnabled(gfx::Feature::WEBRENDER_COMPOSITOR));
2684 
2685   if (gfxConfig::IsEnabled(Feature::WEBRENDER_PARTIAL)) {
2686     gfxVars::SetWebRenderMaxPartialPresentRects(
2687         StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup());
2688   }
2689 
2690   // Set features that affect WR's RendererOptions
2691   gfxVars::SetUseGLSwizzle(
2692       IsFeatureSupported(nsIGfxInfo::FEATURE_GL_SWIZZLE, true));
2693   gfxVars::SetUseWebRenderScissoredCacheClears(IsFeatureSupported(
2694       nsIGfxInfo::FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS, true));
2695 
2696   // The RemoveShaderCacheFromDiskIfNecessary() needs to be called after
2697   // WebRenderConfig initialization.
2698   gfxUtils::RemoveShaderCacheFromDiskIfNecessary();
2699 }
2700 
InitWebGLConfig()2701 void gfxPlatform::InitWebGLConfig() {
2702   // Depends on InitWebRenderConfig() for UseWebRender().
2703 
2704   if (!XRE_IsParentProcess()) return;
2705 
2706   const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
2707 
2708   const auto IsFeatureOk = [&](const int32_t feature) {
2709     nsCString discardFailureId;
2710     int32_t status;
2711     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(
2712         gfxInfo->GetFeatureStatus(feature, discardFailureId, &status)));
2713     return (status == nsIGfxInfo::FEATURE_STATUS_OK);
2714   };
2715 
2716   gfxVars::SetAllowWebgl2(IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL2));
2717   gfxVars::SetWebglAllowWindowsNativeGl(
2718       IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_OPENGL));
2719   gfxVars::SetAllowWebglAccelAngle(
2720       IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_ANGLE));
2721 
2722   if (kIsMacOS) {
2723     // Avoid crash for Intel HD Graphics 3000 on OSX. (Bug 1413269)
2724     nsString vendorID, deviceID;
2725     gfxInfo->GetAdapterVendorID(vendorID);
2726     gfxInfo->GetAdapterDeviceID(deviceID);
2727     if (vendorID.EqualsLiteral("0x8086") &&
2728         (deviceID.EqualsLiteral("0x0116") ||
2729          deviceID.EqualsLiteral("0x0126"))) {
2730       gfxVars::SetWebglAllowCoreProfile(false);
2731     }
2732   }
2733 
2734   bool allowWebGLOop =
2735       IsFeatureOk(nsIGfxInfo::FEATURE_ALLOW_WEBGL_OUT_OF_PROCESS);
2736   gfxVars::SetAllowWebglOop(allowWebGLOop);
2737 
2738   bool threadsafeGL = IsFeatureOk(nsIGfxInfo::FEATURE_THREADSAFE_GL);
2739   threadsafeGL |= StaticPrefs::webgl_threadsafe_gl_force_enabled_AtStartup();
2740   threadsafeGL &= !StaticPrefs::webgl_threadsafe_gl_force_disabled_AtStartup();
2741   gfxVars::SetSupportsThreadsafeGL(threadsafeGL);
2742 
2743   if (kIsAndroid) {
2744     // Don't enable robust buffer access on Adreno 630 devices.
2745     // It causes the linking of some shaders to fail. See bug 1485441.
2746     nsAutoString renderer;
2747     gfxInfo->GetAdapterDeviceID(renderer);
2748     if (renderer.Find("Adreno (TM) 630") != -1) {
2749       gfxVars::SetAllowEglRbab(false);
2750     }
2751   }
2752 }
2753 
InitWebGPUConfig()2754 void gfxPlatform::InitWebGPUConfig() {
2755   FeatureState& feature = gfxConfig::GetFeature(Feature::WEBGPU);
2756   feature.SetDefaultFromPref("dom.webgpu.enabled", true, false);
2757 #ifndef NIGHTLY_BUILD
2758   feature.ForceDisable(FeatureStatus::Blocked,
2759                        "WebGPU can only be enabled in nightly",
2760                        "WEBGPU_DISABLE_NON_NIGHTLY"_ns);
2761 #endif
2762   if (!UseWebRender()) {
2763     feature.ForceDisable(FeatureStatus::UnavailableNoWebRender,
2764                          "WebGPU can't present without WebRender",
2765                          "FEATURE_FAILURE_WEBGPU_NEED_WEBRENDER"_ns);
2766   }
2767 }
2768 
2769 #ifdef XP_WIN
WindowOcclusionPrefChangeCallback(const char * aPref,void *)2770 static void WindowOcclusionPrefChangeCallback(const char* aPref, void*) {
2771   const char* env = PR_GetEnv("MOZ_WINDOW_OCCLUSION");
2772   if (env) {
2773     // env has a higher priority than pref.
2774     return;
2775   }
2776 
2777   FeatureState& feature = gfxConfig::GetFeature(Feature::WINDOW_OCCLUSION);
2778   bool enabled =
2779       StaticPrefs::widget_windows_window_occlusion_tracking_enabled();
2780 
2781   printf_stderr("Dynamically enable window occlusion %d\n", enabled);
2782 
2783   // Update feature before calling WinUtils::EnableWindowOcclusion()
2784   if (enabled) {
2785     feature.UserEnable("User enabled by pref");
2786   } else {
2787     feature.UserDisable("User disabled via pref",
2788                         "FEATURE_FAILURE_PREF_DISABLED"_ns);
2789   }
2790   widget::WinUtils::EnableWindowOcclusion(enabled);
2791 }
2792 #endif
2793 
InitWindowOcclusionConfig()2794 void gfxPlatform::InitWindowOcclusionConfig() {
2795   if (!XRE_IsParentProcess()) {
2796     return;
2797   }
2798 #ifdef XP_WIN
2799   FeatureState& feature = gfxConfig::GetFeature(Feature::WINDOW_OCCLUSION);
2800   feature.SetDefaultFromPref(
2801       StaticPrefs::
2802           GetPrefName_widget_windows_window_occlusion_tracking_enabled(),
2803       true,
2804       StaticPrefs::
2805           GetPrefDefault_widget_windows_window_occlusion_tracking_enabled());
2806 
2807   const char* env = PR_GetEnv("MOZ_WINDOW_OCCLUSION");
2808   if (env) {
2809     if (*env == '1') {
2810       feature.UserForceEnable("Force enabled by envvar");
2811     } else {
2812       feature.UserDisable("Force disabled by envvar",
2813                           "FEATURE_FAILURE_OCCL_ENV"_ns);
2814     }
2815   }
2816 
2817   Preferences::RegisterCallback(
2818       WindowOcclusionPrefChangeCallback,
2819       nsDependentCString(
2820           StaticPrefs::
2821               GetPrefName_widget_windows_window_occlusion_tracking_enabled()));
2822 #endif
2823 }
2824 
CanUseHardwareVideoDecoding()2825 bool gfxPlatform::CanUseHardwareVideoDecoding() {
2826   // this function is called from the compositor thread, so it is not
2827   // safe to init the prefs etc. from here.
2828   MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2829   return sLayersSupportsHardwareVideoDecoding &&
2830          !sLayersHardwareVideoDecodingFailed;
2831 }
2832 
AccelerateLayersByDefault()2833 bool gfxPlatform::AccelerateLayersByDefault() {
2834 #if defined(MOZ_GL_PROVIDER) || defined(MOZ_WIDGET_UIKIT)
2835   return true;
2836 #else
2837   return false;
2838 #endif
2839 }
2840 
2841 /* static */
UsesOffMainThreadCompositing()2842 bool gfxPlatform::UsesOffMainThreadCompositing() {
2843   if (XRE_GetProcessType() == GeckoProcessType_GPU) {
2844     return true;
2845   }
2846 
2847   static bool firstTime = true;
2848   static bool result = false;
2849 
2850   if (firstTime) {
2851     MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2852     result = gfxVars::BrowserTabsRemoteAutostart() ||
2853              !StaticPrefs::
2854                  layers_offmainthreadcomposition_force_disabled_AtStartup();
2855 #if defined(MOZ_WIDGET_GTK)
2856     // Linux users who chose OpenGL are being included in OMTC
2857     result |= StaticPrefs::
2858         layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly();
2859 
2860 #endif
2861     firstTime = false;
2862   }
2863 
2864   return result;
2865 }
2866 
2867 /***
2868  * The preference "layout.frame_rate" has 3 meanings depending on the value:
2869  *
2870  * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw
2871  *      vsync fails.
2872  *  0 = ASAP mode - used during talos testing.
2873  *  X = Software vsync at a rate of X times per second.
2874  */
2875 already_AddRefed<mozilla::gfx::VsyncSource>
CreateHardwareVsyncSource()2876 gfxPlatform::CreateHardwareVsyncSource() {
2877   RefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
2878   return softwareVsync.forget();
2879 }
2880 
2881 /* static */
IsInLayoutAsapMode()2882 bool gfxPlatform::IsInLayoutAsapMode() {
2883   // There are 2 modes of ASAP mode.
2884   // 1 is that the refresh driver and compositor are in lock step
2885   // the second is that the compositor goes ASAP and the refresh driver
2886   // goes at whatever the configurated rate is. This only checks the version
2887   // talos uses, which is the refresh driver and compositor are in lockstep.
2888   return StaticPrefs::layout_frame_rate() == 0;
2889 }
2890 
2891 /* static */
ForceSoftwareVsync()2892 bool gfxPlatform::ForceSoftwareVsync() {
2893   return StaticPrefs::layout_frame_rate() > 0;
2894 }
2895 
2896 /* static */
GetSoftwareVsyncRate()2897 int gfxPlatform::GetSoftwareVsyncRate() {
2898   int preferenceRate = StaticPrefs::layout_frame_rate();
2899   if (preferenceRate <= 0) {
2900     return gfxPlatform::GetDefaultFrameRate();
2901   }
2902   return preferenceRate;
2903 }
2904 
2905 /* static */
GetDefaultFrameRate()2906 int gfxPlatform::GetDefaultFrameRate() { return 60; }
2907 
2908 /* static */
ReInitFrameRate()2909 void gfxPlatform::ReInitFrameRate() {
2910   if (XRE_IsParentProcess()) {
2911     RefPtr<VsyncSource> oldSource = gPlatform->mVsyncSource;
2912 
2913     // Start a new one:
2914     if (gfxPlatform::ForceSoftwareVsync()) {
2915       gPlatform->mVsyncSource =
2916           (gPlatform)->gfxPlatform::CreateHardwareVsyncSource();
2917     } else {
2918       gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource();
2919     }
2920     // Tidy up old vsync source.
2921     if (oldSource) {
2922       oldSource->MoveListenersToNewSource(gPlatform->mVsyncSource);
2923       oldSource->Shutdown();
2924     }
2925   }
2926 }
2927 
GetAzureCanvasBackend() const2928 const char* gfxPlatform::GetAzureCanvasBackend() const {
2929   BackendType backend{};
2930 
2931   if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
2932     // Assume content process' backend prefs.
2933     BackendPrefsData data = GetBackendPrefs();
2934     backend = GetCanvasBackendPref(data.mCanvasBitmask);
2935     if (backend == BackendType::NONE) {
2936       backend = data.mCanvasDefault;
2937     }
2938   } else {
2939     backend = mPreferredCanvasBackend;
2940   }
2941 
2942   return GetBackendName(backend);
2943 }
2944 
GetAzureContentBackend() const2945 const char* gfxPlatform::GetAzureContentBackend() const {
2946   BackendType backend{};
2947 
2948   if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
2949     // Assume content process' backend prefs.
2950     BackendPrefsData data = GetBackendPrefs();
2951     backend = GetContentBackendPref(data.mContentBitmask);
2952     if (backend == BackendType::NONE) {
2953       backend = data.mContentDefault;
2954     }
2955   } else {
2956     backend = mContentBackend;
2957   }
2958 
2959   return GetBackendName(backend);
2960 }
2961 
GetAzureBackendInfo(mozilla::widget::InfoObject & aObj)2962 void gfxPlatform::GetAzureBackendInfo(mozilla::widget::InfoObject& aObj) {
2963   if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
2964     aObj.DefineProperty("AzureCanvasBackend (UI Process)",
2965                         GetBackendName(mPreferredCanvasBackend));
2966     aObj.DefineProperty("AzureFallbackCanvasBackend (UI Process)",
2967                         GetBackendName(mFallbackCanvasBackend));
2968     aObj.DefineProperty("AzureContentBackend (UI Process)",
2969                         GetBackendName(mContentBackend));
2970   } else {
2971     aObj.DefineProperty("AzureFallbackCanvasBackend",
2972                         GetBackendName(mFallbackCanvasBackend));
2973   }
2974 
2975   aObj.DefineProperty("AzureCanvasBackend", GetAzureCanvasBackend());
2976   aObj.DefineProperty("AzureContentBackend", GetAzureContentBackend());
2977 }
2978 
GetApzSupportInfo(mozilla::widget::InfoObject & aObj)2979 void gfxPlatform::GetApzSupportInfo(mozilla::widget::InfoObject& aObj) {
2980   if (!gfxPlatform::AsyncPanZoomEnabled()) {
2981     return;
2982   }
2983 
2984   if (SupportsApzWheelInput()) {
2985     aObj.DefineProperty("ApzWheelInput", 1);
2986   }
2987 
2988   if (SupportsApzTouchInput()) {
2989     aObj.DefineProperty("ApzTouchInput", 1);
2990   }
2991 
2992   if (SupportsApzDragInput()) {
2993     aObj.DefineProperty("ApzDragInput", 1);
2994   }
2995 
2996   if (SupportsApzKeyboardInput() &&
2997       !StaticPrefs::accessibility_browsewithcaret()) {
2998     aObj.DefineProperty("ApzKeyboardInput", 1);
2999   }
3000 
3001   if (SupportsApzAutoscrolling()) {
3002     aObj.DefineProperty("ApzAutoscrollInput", 1);
3003   }
3004 
3005   if (SupportsApzZooming()) {
3006     aObj.DefineProperty("ApzZoomingInput", 1);
3007   }
3008 }
3009 
GetFrameStats(mozilla::widget::InfoObject & aObj)3010 void gfxPlatform::GetFrameStats(mozilla::widget::InfoObject& aObj) {
3011   uint32_t i = 0;
3012   for (FrameStats& f : mFrameStats) {
3013     nsPrintfCString name("Slow Frame #%02u", ++i);
3014 
3015     nsPrintfCString value(
3016         "Frame %" PRIu64
3017         "(%s) CONTENT_FRAME_TIME %d - Transaction start %f, main-thread time "
3018         "%f, full paint time %f, Skipped composites %u, Composite start %f, "
3019         "Resource upload time %f, GPU cache upload time %f, Render time %f, "
3020         "Composite time %f",
3021         f.id().mId, f.url().get(), f.contentFrameTime(),
3022         (f.transactionStart() - f.refreshStart()).ToMilliseconds(),
3023         (f.fwdTime() - f.transactionStart()).ToMilliseconds(),
3024         f.sceneBuiltTime()
3025             ? (f.sceneBuiltTime() - f.transactionStart()).ToMilliseconds()
3026             : 0.0,
3027         f.skippedComposites(),
3028         (f.compositeStart() - f.refreshStart()).ToMilliseconds(),
3029         f.resourceUploadTime(), f.gpuCacheUploadTime(),
3030         (f.compositeEnd() - f.renderStart()).ToMilliseconds(),
3031         (f.compositeEnd() - f.compositeStart()).ToMilliseconds());
3032     aObj.DefineProperty(name.get(), value.get());
3033   }
3034 }
3035 
GetCMSSupportInfo(mozilla::widget::InfoObject & aObj)3036 void gfxPlatform::GetCMSSupportInfo(mozilla::widget::InfoObject& aObj) {
3037   nsTArray<uint8_t> outputProfileData =
3038       gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfileData();
3039   if (outputProfileData.IsEmpty()) {
3040     nsPrintfCString msg("Empty profile data");
3041     aObj.DefineProperty("CMSOutputProfile", msg.get());
3042     return;
3043   }
3044 
3045   // Some profiles can be quite large. We don't want to include giant profiles
3046   // by default in about:support. For now, we only accept less than 8kiB.
3047   const size_t kMaxProfileSize = 8192;
3048   if (outputProfileData.Length() >= kMaxProfileSize) {
3049     nsPrintfCString msg("%zu bytes, too large", outputProfileData.Length());
3050     aObj.DefineProperty("CMSOutputProfile", msg.get());
3051     return;
3052   }
3053 
3054   nsString encodedProfile;
3055   nsresult rv =
3056       Base64Encode(reinterpret_cast<const char*>(outputProfileData.Elements()),
3057                    outputProfileData.Length(), encodedProfile);
3058   if (!NS_SUCCEEDED(rv)) {
3059     nsPrintfCString msg("base64 encode failed 0x%08x",
3060                         static_cast<uint32_t>(rv));
3061     aObj.DefineProperty("CMSOutputProfile", msg.get());
3062     return;
3063   }
3064 
3065   aObj.DefineProperty("CMSOutputProfile", encodedProfile);
3066 }
3067 
GetDisplayInfo(mozilla::widget::InfoObject & aObj)3068 void gfxPlatform::GetDisplayInfo(mozilla::widget::InfoObject& aObj) {
3069   nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
3070 
3071   nsTArray<nsString> displayInfo;
3072   auto rv = gfxInfo->GetDisplayInfo(displayInfo);
3073   if (NS_SUCCEEDED(rv)) {
3074     size_t displayCount = displayInfo.Length();
3075     aObj.DefineProperty("DisplayCount", displayCount);
3076 
3077     for (size_t i = 0; i < displayCount; i++) {
3078       nsPrintfCString name("Display%zu", i);
3079       aObj.DefineProperty(name.get(), displayInfo[i]);
3080     }
3081   }
3082 
3083   // Platform display info is only currently used for about:support and getting
3084   // it might fail in a child process anyway.
3085   if (XRE_IsParentProcess()) {
3086     GetPlatformDisplayInfo(aObj);
3087   }
3088 }
3089 
3090 class FrameStatsComparator {
3091  public:
Equals(const FrameStats & aA,const FrameStats & aB) const3092   bool Equals(const FrameStats& aA, const FrameStats& aB) const {
3093     return aA.contentFrameTime() == aB.contentFrameTime();
3094   }
3095   // Reverse the condition here since we want the array sorted largest to
3096   // smallest.
LessThan(const FrameStats & aA,const FrameStats & aB) const3097   bool LessThan(const FrameStats& aA, const FrameStats& aB) const {
3098     return aA.contentFrameTime() > aB.contentFrameTime();
3099   }
3100 };
3101 
NotifyFrameStats(nsTArray<FrameStats> && aFrameStats)3102 void gfxPlatform::NotifyFrameStats(nsTArray<FrameStats>&& aFrameStats) {
3103   if (!StaticPrefs::gfx_logging_slow_frames_enabled_AtStartup()) {
3104     return;
3105   }
3106 
3107   FrameStatsComparator comp;
3108   for (FrameStats& f : aFrameStats) {
3109     mFrameStats.InsertElementSorted(f, comp);
3110   }
3111   if (mFrameStats.Length() > 10) {
3112     mFrameStats.SetLength(10);
3113   }
3114 }
3115 
3116 /*static*/
TargetFrameRate()3117 uint32_t gfxPlatform::TargetFrameRate() {
3118   if (gPlatform && gPlatform->mVsyncSource) {
3119     VsyncSource::Display& display = gPlatform->mVsyncSource->GetGlobalDisplay();
3120     return round(1000.0 / display.GetVsyncRate().ToMilliseconds());
3121   }
3122   return 0;
3123 }
3124 
3125 /* static */
UseDesktopZoomingScrollbars()3126 bool gfxPlatform::UseDesktopZoomingScrollbars() {
3127   return StaticPrefs::apz_allow_zooming() &&
3128          !StaticPrefs::apz_force_disable_desktop_zooming_scrollbars();
3129 }
3130 
3131 /*static*/
AsyncPanZoomEnabled()3132 bool gfxPlatform::AsyncPanZoomEnabled() {
3133 #if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
3134   // For XUL applications (everything but Firefox on Android)
3135   // we only want to use APZ when E10S is enabled. If
3136   // we ever get input events off the main thread we can consider relaxing
3137   // this requirement.
3138   if (!BrowserTabsRemoteAutostart()) {
3139     return false;
3140   }
3141 #endif
3142 #ifdef MOZ_WIDGET_ANDROID
3143   return true;
3144 #else
3145   // If Fission is enabled, OOP iframes require APZ for hittest.  So, we
3146   // need to forcibly enable APZ in that case for avoiding users confused.
3147   if (FissionAutostart()) {
3148     return true;
3149   }
3150   return StaticPrefs::
3151       layers_async_pan_zoom_enabled_AtStartup_DoNotUseDirectly();
3152 #endif
3153 }
3154 
3155 /*static*/
PerfWarnings()3156 bool gfxPlatform::PerfWarnings() {
3157   return StaticPrefs::gfx_perf_warnings_enabled();
3158 }
3159 
NotifyCompositorCreated(LayersBackend aBackend)3160 void gfxPlatform::NotifyCompositorCreated(LayersBackend aBackend) {
3161   if (mCompositorBackend == aBackend) {
3162     return;
3163   }
3164 
3165   if (mCompositorBackend != LayersBackend::LAYERS_NONE) {
3166     gfxCriticalNote << "Compositors might be mixed (" << int(mCompositorBackend)
3167                     << "," << int(aBackend) << ")";
3168   }
3169 
3170   // Set the backend before we notify so it's available immediately.
3171   mCompositorBackend = aBackend;
3172 
3173   if (XRE_IsParentProcess()) {
3174     Telemetry::ScalarSet(
3175         Telemetry::ScalarID::GFX_COMPOSITOR,
3176         NS_ConvertUTF8toUTF16(GetLayersBackendName(mCompositorBackend)));
3177 
3178     nsCString geckoVersion;
3179     nsCOMPtr<nsIXULAppInfo> app = do_GetService("@mozilla.org/xre/app-info;1");
3180     if (app) {
3181       app->GetVersion(geckoVersion);
3182     }
3183     Telemetry::ScalarSet(Telemetry::ScalarID::GFX_LAST_COMPOSITOR_GECKO_VERSION,
3184                          NS_ConvertASCIItoUTF16(geckoVersion));
3185 
3186     Telemetry::ScalarSet(
3187         Telemetry::ScalarID::GFX_FEATURE_WEBRENDER,
3188         NS_ConvertUTF8toUTF16(gfxConfig::GetFeature(gfx::Feature::WEBRENDER)
3189                                   .GetStatusAndFailureIdString()));
3190   }
3191 
3192   // Notify that we created a compositor, so telemetry can update.
3193   NS_DispatchToMainThread(
3194       NS_NewRunnableFunction("gfxPlatform::NotifyCompositorCreated", [] {
3195         if (nsCOMPtr<nsIObserverService> obsvc =
3196                 services::GetObserverService()) {
3197           obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
3198         }
3199       }));
3200 }
3201 
3202 /* static */
FallbackFromAcceleration(FeatureStatus aStatus,const char * aMessage,const nsACString & aFailureId)3203 bool gfxPlatform::FallbackFromAcceleration(FeatureStatus aStatus,
3204                                            const char* aMessage,
3205                                            const nsACString& aFailureId) {
3206   // We always want to ensure (Hardware) WebRender is disabled.
3207   if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
3208     gfxConfig::GetFeature(Feature::WEBRENDER)
3209         .ForceDisable(aStatus, aMessage, aFailureId);
3210   }
3211 
3212   // Determine whether or not we are allowed to use Software WebRender in
3213   // fallback without the GPU process. Either the pref is false, or the feature
3214   // is enabled and we are currently still using it.
3215   bool swglFallbackAllowed =
3216       !StaticPrefs::
3217           gfx_webrender_fallback_software_requires_gpu_process_AtStartup() ||
3218       gfxConfig::IsEnabled(Feature::GPU_PROCESS);
3219 
3220 #ifdef XP_WIN
3221   // Before we disable D3D11 and HW_COMPOSITING, we should check if we can
3222   // fallback from WebRender to Software WebRender + D3D11 compositing.
3223   if (StaticPrefs::gfx_webrender_fallback_software_d3d11_AtStartup() &&
3224       swglFallbackAllowed && gfxVars::AllowSoftwareWebRenderD3D11() &&
3225       gfxConfig::IsEnabled(Feature::WEBRENDER_SOFTWARE) &&
3226       gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING) &&
3227       gfxVars::UseWebRender() && !gfxVars::UseSoftwareWebRender()) {
3228     // Fallback to Software WebRender + D3D11 compositing.
3229     gfxCriticalNote << "Fallback WR to SW-WR + D3D11";
3230     gfxVars::SetUseSoftwareWebRender(true);
3231     return true;
3232   }
3233 
3234   if (StaticPrefs::gfx_webrender_fallback_software_d3d11_AtStartup() &&
3235       swglFallbackAllowed && gfxVars::AllowSoftwareWebRenderD3D11() &&
3236       gfxVars::UseSoftwareWebRender()) {
3237     // Fallback from Software WebRender + D3D11 to Software WebRender.
3238     gfxCriticalNote << "Fallback SW-WR + D3D11 to SW-WR";
3239     gfxVars::SetAllowSoftwareWebRenderD3D11(false);
3240     return true;
3241   }
3242 
3243   // We aren't using Software WebRender + D3D11 compositing, so turn off the
3244   // D3D11 and D2D.
3245   if (gfxConfig::IsEnabled(Feature::DIRECT2D)) {
3246     gfxConfig::GetFeature(Feature::DIRECT2D)
3247         .ForceDisable(aStatus, aMessage, aFailureId);
3248   }
3249   if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
3250     gfxConfig::GetFeature(Feature::D3D11_COMPOSITING)
3251         .ForceDisable(aStatus, aMessage, aFailureId);
3252 
3253     if (StaticPrefs::gfx_webrender_fallback_software_AtStartup() &&
3254         swglFallbackAllowed &&
3255         gfxConfig::IsEnabled(Feature::WEBRENDER_SOFTWARE) &&
3256         !gfxVars::UseWebRender()) {
3257       // Fallback from D3D11 to Software WebRender.
3258       gfxCriticalNote << "Fallback D3D11 to SW-WR";
3259       gfxVars::SetUseWebRender(true);
3260       gfxVars::SetUseSoftwareWebRender(true);
3261       return true;
3262     }
3263   }
3264 #endif
3265 
3266 #ifndef MOZ_WIDGET_ANDROID
3267   // Non-Android wants to fallback to Software WebRender or Basic. Android wants
3268   // to fallback to OpenGL.
3269   if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
3270     gfxConfig::GetFeature(Feature::HW_COMPOSITING)
3271         .ForceDisable(aStatus, aMessage, aFailureId);
3272   }
3273 #endif
3274 
3275   if (!gfxVars::UseWebRender()) {
3276     // We were not using WebRender in the first place, and we have disabled
3277     // all forms of accelerated compositing.
3278     return false;
3279   }
3280 
3281   if (StaticPrefs::gfx_webrender_fallback_software_AtStartup() &&
3282       swglFallbackAllowed &&
3283       gfxConfig::IsEnabled(Feature::WEBRENDER_SOFTWARE) &&
3284       !gfxVars::UseSoftwareWebRender()) {
3285     // Fallback from WebRender to Software WebRender.
3286     gfxCriticalNote << "Fallback WR to SW-WR";
3287     gfxVars::SetUseSoftwareWebRender(true);
3288     return true;
3289   }
3290 
3291   MOZ_ASSERT(gfxVars::UseWebRender());
3292 
3293   if (!gfxVars::UseSoftwareWebRender()) {
3294     // Software WebRender may be disabled due to a startup issue with the
3295     // blocklist, despite it being our only fallback option based on the prefs.
3296     // If WebRender is unable to be initialized, this means that user would
3297     // otherwise get stuck with WebRender. As such, force a switch to Software
3298     // WebRender in this case.
3299     gfxCriticalNoteOnce << "Fallback WR to SW-WR, forced";
3300     gfxVars::SetUseSoftwareWebRender(true);
3301     return true;
3302   }
3303 
3304   // Continue using Software WebRender (disabled fallback to Basic).
3305   gfxCriticalNoteOnce << "Fallback remains SW-WR";
3306   return false;
3307 }
3308 
3309 /* static */
DisableGPUProcess()3310 void gfxPlatform::DisableGPUProcess() {
3311   gfxVars::SetRemoteCanvasEnabled(false);
3312 
3313   if (gfxVars::UseWebRender()) {
3314     // We need to initialize the parent process to prepare for WebRender if we
3315     // did not end up disabling it, despite losing the GPU process.
3316     wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());
3317     image::ImageMemoryReporter::InitForWebRender();
3318   }
3319 }
3320 
FetchAndImportContentDeviceData()3321 void gfxPlatform::FetchAndImportContentDeviceData() {
3322   MOZ_ASSERT(XRE_IsContentProcess());
3323 
3324   if (gContentDeviceInitData) {
3325     ImportContentDeviceData(*gContentDeviceInitData);
3326     return;
3327   }
3328 
3329   mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
3330 
3331   mozilla::gfx::ContentDeviceData data;
3332   cc->SendGetGraphicsDeviceInitData(&data);
3333 
3334   ImportContentDeviceData(data);
3335 }
3336 
ImportContentDeviceData(const mozilla::gfx::ContentDeviceData & aData)3337 void gfxPlatform::ImportContentDeviceData(
3338     const mozilla::gfx::ContentDeviceData& aData) {
3339   MOZ_ASSERT(XRE_IsContentProcess());
3340 
3341   const DevicePrefs& prefs = aData.prefs();
3342   gfxConfig::Inherit(Feature::HW_COMPOSITING, prefs.hwCompositing());
3343   gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, prefs.oglCompositing());
3344 }
3345 
BuildContentDeviceData(mozilla::gfx::ContentDeviceData * aOut)3346 void gfxPlatform::BuildContentDeviceData(
3347     mozilla::gfx::ContentDeviceData* aOut) {
3348   MOZ_ASSERT(XRE_IsParentProcess());
3349 
3350   // Make sure our settings are synchronized from the GPU process.
3351   GPUProcessManager::Get()->EnsureGPUReady();
3352 
3353   aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
3354   aOut->prefs().oglCompositing() =
3355       gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
3356 }
3357 
ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData & aData)3358 void gfxPlatform::ImportGPUDeviceData(
3359     const mozilla::gfx::GPUDeviceData& aData) {
3360   MOZ_ASSERT(XRE_IsParentProcess());
3361 
3362   gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
3363 }
3364 
SupportsApzTouchInput() const3365 bool gfxPlatform::SupportsApzTouchInput() const {
3366   return dom::TouchEvent::PrefEnabled(nullptr);
3367 }
3368 
SupportsApzDragInput() const3369 bool gfxPlatform::SupportsApzDragInput() const {
3370   return StaticPrefs::apz_drag_enabled();
3371 }
3372 
SupportsApzKeyboardInput() const3373 bool gfxPlatform::SupportsApzKeyboardInput() const {
3374   return StaticPrefs::apz_keyboard_enabled_AtStartup();
3375 }
3376 
SupportsApzAutoscrolling() const3377 bool gfxPlatform::SupportsApzAutoscrolling() const {
3378   return StaticPrefs::apz_autoscroll_enabled();
3379 }
3380 
SupportsApzZooming() const3381 bool gfxPlatform::SupportsApzZooming() const {
3382   return StaticPrefs::apz_allow_zooming();
3383 }
3384 
InitOpenGLConfig()3385 void gfxPlatform::InitOpenGLConfig() {
3386 #ifdef XP_WIN
3387   // Don't enable by default on Windows, since it could show up in about:support
3388   // even though it'll never get used. Only attempt if user enables the pref
3389   if (!Preferences::GetBool("layers.prefer-opengl")) {
3390     return;
3391   }
3392 #endif
3393 
3394   FeatureState& openGLFeature =
3395       gfxConfig::GetFeature(Feature::OPENGL_COMPOSITING);
3396 
3397   // Check to see hw comp supported
3398   if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
3399     openGLFeature.DisableByDefault(FeatureStatus::Unavailable,
3400                                    "Hardware compositing is disabled",
3401                                    "FEATURE_FAILURE_OPENGL_NEED_HWCOMP"_ns);
3402     return;
3403   }
3404 
3405 #ifdef XP_WIN
3406   openGLFeature.SetDefaultFromPref(
3407       StaticPrefs::GetPrefName_layers_prefer_opengl(), true,
3408       StaticPrefs::GetPrefDefault_layers_prefer_opengl());
3409 #else
3410   openGLFeature.EnableByDefault();
3411 #endif
3412 
3413   // When layers acceleration is force-enabled, enable it even for blocklisted
3414   // devices.
3415   if (StaticPrefs::
3416           layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly()) {
3417     openGLFeature.UserForceEnable("Force-enabled by pref");
3418     return;
3419   }
3420 
3421   nsCString message;
3422   nsCString failureId;
3423   if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &message,
3424                            failureId)) {
3425     openGLFeature.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
3426   }
3427 }
3428 
IsGfxInfoStatusOkay(int32_t aFeature,nsCString * aOutMessage,nsCString & aFailureId)3429 bool gfxPlatform::IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage,
3430                                       nsCString& aFailureId) {
3431   nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
3432   if (!gfxInfo) {
3433     return true;
3434   }
3435 
3436   int32_t status;
3437   if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) &&
3438       status != nsIGfxInfo::FEATURE_STATUS_OK) {
3439     aOutMessage->AssignLiteral("#BLOCKLIST_");
3440     aOutMessage->AppendASCII(aFailureId.get());
3441     return false;
3442   }
3443 
3444   return true;
3445 }
3446