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