Bug 1771374 - Disable color management based on pref in DCLayerTree. r=jrmuizel
[gecko.git] / gfx / thebes / gfxPlatform.cpp
blobf864c730fd0251ca7d5a6d28e3c74c7ec38cc8d6
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/. */
6 #include "mozilla/FontPropertyTypes.h"
7 #include "mozilla/RDDProcessManager.h"
8 #include "mozilla/image/ImageMemoryReporter.h"
9 #include "mozilla/layers/CompositorManagerChild.h"
10 #include "mozilla/layers/CompositorThread.h"
11 #include "mozilla/layers/ImageBridgeChild.h"
12 #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
13 #include "mozilla/layers/CompositorBridgeChild.h"
14 #include "mozilla/layers/RemoteTextureMap.h"
15 #include "mozilla/webrender/RenderThread.h"
16 #include "mozilla/webrender/WebRenderAPI.h"
17 #include "mozilla/webrender/webrender_ffi.h"
18 #include "mozilla/gfx/BuildConstants.h"
19 #include "mozilla/gfx/gfxConfigManager.h"
20 #include "mozilla/gfx/gfxVars.h"
21 #include "mozilla/gfx/GPUProcessManager.h"
22 #include "mozilla/gfx/GraphicsMessages.h"
23 #include "mozilla/gfx/CanvasManagerChild.h"
24 #include "mozilla/gfx/CanvasManagerParent.h"
25 #include "mozilla/ClearOnShutdown.h"
26 #include "mozilla/EnumTypeTraits.h"
27 #include "mozilla/StaticPrefs_accessibility.h"
28 #include "mozilla/StaticPrefs_apz.h"
29 #include "mozilla/StaticPrefs_bidi.h"
30 #include "mozilla/StaticPrefs_canvas.h"
31 #include "mozilla/StaticPrefs_gfx.h"
32 #include "mozilla/StaticPrefs_layout.h"
33 #include "mozilla/StaticPrefs_layers.h"
34 #include "mozilla/StaticPrefs_media.h"
35 #include "mozilla/StaticPrefs_privacy.h"
36 #include "mozilla/StaticPrefs_webgl.h"
37 #include "mozilla/StaticPrefs_widget.h"
38 #include "mozilla/Telemetry.h"
39 #include "mozilla/TimeStamp.h"
40 #include "mozilla/Unused.h"
41 #include "mozilla/IntegerPrintfMacros.h"
42 #include "mozilla/Base64.h"
43 #include "mozilla/VsyncDispatcher.h"
45 #include "mozilla/Logging.h"
46 #include "mozilla/Components.h"
47 #include "nsAppRunner.h"
48 #include "nsAppDirectoryServiceDefs.h"
49 #include "nsCSSProps.h"
51 #include "gfxCrashReporterUtils.h"
52 #include "gfxPlatform.h"
54 #include "gfxBlur.h"
55 #include "gfxEnv.h"
56 #include "gfxTextRun.h"
57 #include "gfxUserFontSet.h"
58 #include "gfxConfig.h"
59 #include "GfxDriverInfo.h"
60 #include "VRProcessManager.h"
61 #include "VRThread.h"
63 #ifdef XP_WIN
64 # include <process.h>
65 # define getpid _getpid
66 #else
67 # include <unistd.h>
68 #endif
70 #include "nsXULAppAPI.h"
71 #include "nsIXULAppInfo.h"
72 #include "nsDirectoryServiceUtils.h"
73 #include "nsDirectoryServiceDefs.h"
75 #if defined(XP_WIN)
76 # include "gfxWindowsPlatform.h"
77 # include "mozilla/widget/WinWindowOcclusionTracker.h"
78 #elif defined(XP_MACOSX)
79 # include "gfxPlatformMac.h"
80 # include "gfxQuartzSurface.h"
81 # include "nsCocoaFeatures.h"
82 #elif defined(MOZ_WIDGET_GTK)
83 # include "gfxPlatformGtk.h"
84 #elif defined(ANDROID)
85 # include "gfxAndroidPlatform.h"
86 #endif
87 #if defined(MOZ_WIDGET_ANDROID)
88 # include "mozilla/jni/Utils.h" // for IsFennec
89 #endif
91 #ifdef XP_WIN
92 # include "mozilla/WindowsVersion.h"
93 # include "WinUtils.h"
94 #endif
96 #include "nsGkAtoms.h"
97 #include "gfxPlatformFontList.h"
98 #include "gfxContext.h"
99 #include "gfxImageSurface.h"
100 #include "nsUnicodeProperties.h"
101 #include "harfbuzz/hb.h"
102 #include "gfxGraphiteShaper.h"
103 #include "gfx2DGlue.h"
104 #include "gfxGradientCache.h"
105 #include "gfxUtils.h" // for NextPowerOfTwo
106 #include "gfxFontMissingGlyphs.h"
108 #include "nsExceptionHandler.h"
109 #include "nsServiceManagerUtils.h"
110 #include "nsTArray.h"
111 #include "nsIObserverService.h"
112 #include "mozilla/widget/Screen.h"
113 #include "mozilla/widget/ScreenManager.h"
114 #include "MainThreadUtils.h"
116 #include "nsWeakReference.h"
118 #include "cairo.h"
119 #include "qcms.h"
121 #include "imgITools.h"
123 #include "plstr.h"
124 #include "nsCRT.h"
125 #include "GLContext.h"
126 #include "GLContextProvider.h"
127 #include "mozilla/gfx/Logging.h"
129 #ifdef __GNUC__
130 # pragma GCC diagnostic push
131 # pragma GCC diagnostic ignored "-Wshadow"
132 #endif
133 #include "skia/include/core/SkGraphics.h"
134 #ifdef MOZ_ENABLE_FREETYPE
135 # include "skia/include/ports/SkTypeface_cairo.h"
136 #endif
137 #include "mozilla/gfx/SkMemoryReporter.h"
138 #ifdef __GNUC__
139 # pragma GCC diagnostic pop // -Wshadow
140 #endif
141 static const uint32_t kDefaultGlyphCacheSize = -1;
143 #include "mozilla/Preferences.h"
144 #include "mozilla/Assertions.h"
145 #include "mozilla/Atomics.h"
146 #include "mozilla/Attributes.h"
147 #include "mozilla/Mutex.h"
149 #include "nsAlgorithm.h"
150 #include "nsIGfxInfo.h"
151 #include "nsIXULRuntime.h"
152 #include "VsyncSource.h"
153 #include "SoftwareVsyncSource.h"
154 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
155 #include "mozilla/dom/ContentChild.h"
156 #include "mozilla/dom/ContentParent.h"
157 #include "mozilla/dom/TouchEvent.h"
158 #include "gfxVR.h"
159 #include "VRManager.h"
160 #include "VRManagerChild.h"
161 #include "mozilla/gfx/GPUParent.h"
162 #include "prsystem.h"
164 #include "mozilla/gfx/2D.h"
165 #include "mozilla/gfx/SourceSurfaceCairo.h"
167 using namespace mozilla;
168 using namespace mozilla::layers;
169 using namespace mozilla::gl;
170 using namespace mozilla::gfx;
172 gfxPlatform* gPlatform = nullptr;
173 static bool gEverInitialized = false;
175 const ContentDeviceData* gContentDeviceInitData = nullptr;
177 Atomic<bool, MemoryOrdering::ReleaseAcquire> gfxPlatform::gCMSInitialized;
178 CMSMode gfxPlatform::gCMSMode = CMSMode::Off;
180 // These two may point to the same profile
181 qcms_profile* gfxPlatform::gCMSOutputProfile = nullptr;
182 qcms_profile* gfxPlatform::gCMSsRGBProfile = nullptr;
184 qcms_transform* gfxPlatform::gCMSRGBTransform = nullptr;
185 qcms_transform* gfxPlatform::gCMSInverseRGBTransform = nullptr;
186 qcms_transform* gfxPlatform::gCMSRGBATransform = nullptr;
187 qcms_transform* gfxPlatform::gCMSBGRATransform = nullptr;
189 /// This override of the LogForwarder, initially used for the critical graphics
190 /// errors, is sending the log to the crash annotations as well, but only
191 /// if the capacity set with the method below is >= 2. We always retain the
192 /// very first critical message, and the latest capacity-1 messages are
193 /// rotated through. Note that we don't expect the total number of times
194 /// this gets called to be large - it is meant for critical errors only.
196 class CrashStatsLogForwarder : public mozilla::gfx::LogForwarder {
197 public:
198 explicit CrashStatsLogForwarder(CrashReporter::Annotation aKey);
199 void Log(const std::string& aString) override;
200 void CrashAction(LogReason aReason) override;
201 bool UpdateStringsVector(const std::string& aString) override;
203 LoggingRecord LoggingRecordCopy() override;
205 void SetCircularBufferSize(uint32_t aCapacity);
207 private:
208 // Helper for the Log()
209 void UpdateCrashReport();
211 private:
212 LoggingRecord mBuffer;
213 CrashReporter::Annotation mCrashCriticalKey;
214 uint32_t mMaxCapacity;
215 int32_t mIndex;
216 Mutex mMutex MOZ_UNANNOTATED;
219 CrashStatsLogForwarder::CrashStatsLogForwarder(CrashReporter::Annotation aKey)
220 : mBuffer(),
221 mCrashCriticalKey(aKey),
222 mMaxCapacity(0),
223 mIndex(-1),
224 mMutex("CrashStatsLogForwarder") {}
226 void CrashStatsLogForwarder::SetCircularBufferSize(uint32_t aCapacity) {
227 MutexAutoLock lock(mMutex);
229 mMaxCapacity = aCapacity;
230 mBuffer.reserve(static_cast<size_t>(aCapacity));
233 LoggingRecord CrashStatsLogForwarder::LoggingRecordCopy() {
234 MutexAutoLock lock(mMutex);
235 return mBuffer;
238 bool CrashStatsLogForwarder::UpdateStringsVector(const std::string& aString) {
239 // We want at least the first one and the last one. Otherwise, no point.
240 if (mMaxCapacity < 2) {
241 return false;
244 mIndex += 1;
245 MOZ_ASSERT(mIndex >= 0);
247 // index will count 0, 1, 2, ..., max-1, 1, 2, ..., max-1, 1, 2, ...
248 int32_t index = mIndex ? (mIndex - 1) % (mMaxCapacity - 1) + 1 : 0;
249 MOZ_ASSERT(index >= 0 && index < (int32_t)mMaxCapacity);
250 MOZ_ASSERT(index <= mIndex && index <= (int32_t)mBuffer.size());
252 double tStamp = (TimeStamp::NowLoRes() - TimeStamp::ProcessCreation())
253 .ToSecondsSigDigits();
255 // Checking for index >= mBuffer.size(), rather than index == mBuffer.size()
256 // just out of paranoia, but we know index <= mBuffer.size().
257 LoggingRecordEntry newEntry(mIndex, aString, tStamp);
258 if (index >= static_cast<int32_t>(mBuffer.size())) {
259 mBuffer.push_back(newEntry);
260 } else {
261 mBuffer[index] = newEntry;
263 return true;
266 void CrashStatsLogForwarder::UpdateCrashReport() {
267 std::stringstream message;
268 std::string logAnnotation;
270 switch (XRE_GetProcessType()) {
271 case GeckoProcessType_Default:
272 logAnnotation = "|[";
273 break;
274 case GeckoProcessType_Content:
275 logAnnotation = "|[C";
276 break;
277 case GeckoProcessType_GPU:
278 logAnnotation = "|[G";
279 break;
280 default:
281 logAnnotation = "|[X";
282 break;
285 for (auto& it : mBuffer) {
286 message << logAnnotation << Get<0>(it) << "]" << Get<1>(it)
287 << " (t=" << Get<2>(it) << ") ";
290 nsCString reportString(message.str().c_str());
291 nsresult annotated =
292 CrashReporter::AnnotateCrashReport(mCrashCriticalKey, reportString);
294 if (annotated != NS_OK) {
295 printf("Crash Annotation %s: %s",
296 CrashReporter::AnnotationToString(mCrashCriticalKey),
297 message.str().c_str());
301 class LogForwarderEvent : public Runnable {
302 virtual ~LogForwarderEvent() = default;
304 public:
305 NS_INLINE_DECL_REFCOUNTING_INHERITED(LogForwarderEvent, Runnable)
307 explicit LogForwarderEvent(const nsCString& aMessage)
308 : mozilla::Runnable("LogForwarderEvent"), mMessage(aMessage) {}
310 NS_IMETHOD Run() override {
311 MOZ_ASSERT(NS_IsMainThread() &&
312 (XRE_IsContentProcess() || XRE_IsGPUProcess()));
314 if (XRE_IsContentProcess()) {
315 dom::ContentChild* cc = dom::ContentChild::GetSingleton();
316 Unused << cc->SendGraphicsError(mMessage);
317 } else if (XRE_IsGPUProcess()) {
318 GPUParent* gp = GPUParent::GetSingleton();
319 Unused << gp->SendGraphicsError(mMessage);
322 return NS_OK;
325 protected:
326 nsCString mMessage;
329 void CrashStatsLogForwarder::Log(const std::string& aString) {
330 MutexAutoLock lock(mMutex);
332 if (UpdateStringsVector(aString)) {
333 UpdateCrashReport();
336 // Add it to the parent strings
337 if (!XRE_IsParentProcess()) {
338 nsCString stringToSend(aString.c_str());
339 if (NS_IsMainThread()) {
340 if (XRE_IsContentProcess()) {
341 dom::ContentChild* cc = dom::ContentChild::GetSingleton();
342 Unused << cc->SendGraphicsError(stringToSend);
343 } else if (XRE_IsGPUProcess()) {
344 GPUParent* gp = GPUParent::GetSingleton();
345 Unused << gp->SendGraphicsError(stringToSend);
347 } else {
348 nsCOMPtr<nsIRunnable> r1 = new LogForwarderEvent(stringToSend);
349 NS_DispatchToMainThread(r1);
354 class CrashTelemetryEvent : public Runnable {
355 virtual ~CrashTelemetryEvent() = default;
357 public:
358 NS_INLINE_DECL_REFCOUNTING_INHERITED(CrashTelemetryEvent, Runnable)
360 explicit CrashTelemetryEvent(uint32_t aReason)
361 : mozilla::Runnable("CrashTelemetryEvent"), mReason(aReason) {}
363 NS_IMETHOD Run() override {
364 MOZ_ASSERT(NS_IsMainThread());
365 Telemetry::Accumulate(Telemetry::GFX_CRASH, mReason);
366 return NS_OK;
369 protected:
370 uint32_t mReason;
373 void CrashStatsLogForwarder::CrashAction(LogReason aReason) {
374 #ifndef RELEASE_OR_BETA
375 // Non-release builds crash by default, but will use telemetry
376 // if this environment variable is present.
377 static bool useTelemetry = gfxEnv::GfxDevCrashTelemetry();
378 #else
379 // Release builds use telemetry by default, but will crash instead
380 // if this environment variable is present.
381 static bool useTelemetry = !gfxEnv::GfxDevCrashMozCrash();
382 #endif
384 if (useTelemetry) {
385 // The callers need to assure that aReason is in the range
386 // that the telemetry call below supports.
387 if (NS_IsMainThread()) {
388 Telemetry::Accumulate(Telemetry::GFX_CRASH, (uint32_t)aReason);
389 } else {
390 nsCOMPtr<nsIRunnable> r1 = new CrashTelemetryEvent((uint32_t)aReason);
391 NS_DispatchToMainThread(r1);
393 } else {
394 // ignoring aReason, we can get the information we need from the stack
395 MOZ_CRASH("GFX_CRASH");
399 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
401 #define GFX_PREF_FALLBACK_USE_CMAPS \
402 "gfx.font_rendering.fallback.always_use_cmaps"
404 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
406 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
407 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
409 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
410 #if defined(XP_MACOSX)
411 # define GFX_PREF_CORETEXT_SHAPING "gfx.font_rendering.coretext.enabled"
412 #endif
414 #define FONT_VARIATIONS_PREF "layout.css.font-variations.enabled"
416 static const char* kObservedPrefs[] = {"gfx.downloadable_fonts.",
417 "gfx.font_rendering.", nullptr};
419 static void FontPrefChanged(const char* aPref, void* aData) {
420 MOZ_ASSERT(aPref);
421 NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
422 gfxPlatform::GetPlatform()->FontsPrefsChanged(aPref);
425 void gfxPlatform::OnMemoryPressure(layers::MemoryPressureReason aWhy) {
426 Factory::PurgeAllCaches();
427 gfxGradientCache::PurgeAllCaches();
428 gfxFontMissingGlyphs::Purge();
429 PurgeSkiaFontCache();
430 if (XRE_IsParentProcess()) {
431 layers::CompositorManagerChild* manager =
432 CompositorManagerChild::GetInstance();
433 if (manager) {
434 manager->SendNotifyMemoryPressure();
439 gfxPlatform::gfxPlatform()
440 : mHasVariationFontSupport(false),
441 mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo),
442 mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo),
443 mFrameStatsCollector(this, &gfxPlatform::GetFrameStats),
444 mCMSInfoCollector(this, &gfxPlatform::GetCMSSupportInfo),
445 mDisplayInfoCollector(this, &gfxPlatform::GetDisplayInfo),
446 mOverlayInfoCollector(this, &gfxPlatform::GetOverlayInfo),
447 mCompositorBackend(layers::LayersBackend::LAYERS_NONE),
448 mScreenDepth(0) {
449 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
451 InitBackendPrefs(GetBackendPrefs());
452 VRManager::ManagerInit();
455 gfxPlatform* gfxPlatform::GetPlatform() {
456 if (!gPlatform) {
457 MOZ_RELEASE_ASSERT(!XRE_IsContentProcess(),
458 "Content Process should have called InitChild() before "
459 "first GetPlatform()");
460 Init();
462 return gPlatform;
465 bool gfxPlatform::Initialized() { return !!gPlatform; }
467 /* static */
468 void gfxPlatform::InitChild(const ContentDeviceData& aData) {
469 MOZ_ASSERT(XRE_IsContentProcess());
470 MOZ_RELEASE_ASSERT(!gPlatform,
471 "InitChild() should be called before first GetPlatform()");
472 // Make the provided initial ContentDeviceData available to the init
473 // routines, so they don't have to do a sync request from the parent.
474 gContentDeviceInitData = &aData;
475 Init();
476 gContentDeviceInitData = nullptr;
479 #define WR_DEBUG_PREF "gfx.webrender.debug"
481 static void SwapIntervalPrefChangeCallback(const char* aPrefName, void*) {
482 bool egl = Preferences::GetBool("gfx.swap-interval.egl", false);
483 bool glx = Preferences::GetBool("gfx.swap-interval.glx", false);
484 gfxVars::SetSwapIntervalEGL(egl);
485 gfxVars::SetSwapIntervalGLX(glx);
488 static void WebRendeProfilerUIPrefChangeCallback(const char* aPrefName, void*) {
489 nsCString uiString;
490 if (NS_SUCCEEDED(Preferences::GetCString("gfx.webrender.debug.profiler-ui",
491 uiString))) {
492 gfxVars::SetWebRenderProfilerUI(uiString);
496 // List of boolean dynamic parameter for WebRender.
498 // The parameters in this list are:
499 // - The pref name.
500 // - The BoolParameter enum variant (see webrender_api/src/lib.rs)
501 // - A default value.
502 #define WR_BOOL_PARAMETER_LIST(_) \
503 _("gfx.webrender.batched-texture-uploads", \
504 wr::BoolParameter::BatchedUploads, true) \
505 _("gfx.webrender.draw-calls-for-texture-copy", \
506 wr::BoolParameter::DrawCallsForTextureCopy, true) \
507 _("gfx.webrender.pbo-uploads", wr::BoolParameter::PboUploads, true) \
508 _("gfx.webrender.multithreading", wr::BoolParameter::Multithreading, true)
510 static void WebRenderBoolParameterChangeCallback(const char*, void*) {
511 uint32_t bits = 0;
513 #define WR_BOOL_PARAMETER(name, key, default_val) \
514 if (Preferences::GetBool(name, default_val)) { \
515 bits |= 1 << (uint32_t)key; \
518 WR_BOOL_PARAMETER_LIST(WR_BOOL_PARAMETER)
519 #undef WR_BOOL_PARAMETER
521 gfx::gfxVars::SetWebRenderBoolParameters(bits);
524 static void RegisterWebRenderBoolParamCallback() {
525 #define WR_BOOL_PARAMETER(name, _key, _default_val) \
526 Preferences::RegisterCallback(WebRenderBoolParameterChangeCallback, name);
528 WR_BOOL_PARAMETER_LIST(WR_BOOL_PARAMETER)
529 #undef WR_BOOL_PARAMETER
531 WebRenderBoolParameterChangeCallback(nullptr, nullptr);
534 static void WebRenderDebugPrefChangeCallback(const char* aPrefName, void*) {
535 wr::DebugFlags flags{0};
536 #define GFX_WEBRENDER_DEBUG(suffix, bit) \
537 if (Preferences::GetBool(WR_DEBUG_PREF suffix, false)) { \
538 flags |= (bit); \
541 GFX_WEBRENDER_DEBUG(".profiler", wr::DebugFlags::PROFILER_DBG)
542 GFX_WEBRENDER_DEBUG(".render-targets", wr::DebugFlags::RENDER_TARGET_DBG)
543 GFX_WEBRENDER_DEBUG(".texture-cache", wr::DebugFlags::TEXTURE_CACHE_DBG)
544 GFX_WEBRENDER_DEBUG(".gpu-time-queries", wr::DebugFlags::GPU_TIME_QUERIES)
545 GFX_WEBRENDER_DEBUG(".gpu-sample-queries", wr::DebugFlags::GPU_SAMPLE_QUERIES)
546 GFX_WEBRENDER_DEBUG(".disable-batching", wr::DebugFlags::DISABLE_BATCHING)
547 GFX_WEBRENDER_DEBUG(".epochs", wr::DebugFlags::EPOCHS)
548 GFX_WEBRENDER_DEBUG(".smart-profiler", wr::DebugFlags::SMART_PROFILER)
549 GFX_WEBRENDER_DEBUG(".echo-driver-messages",
550 wr::DebugFlags::ECHO_DRIVER_MESSAGES)
551 GFX_WEBRENDER_DEBUG(".show-overdraw", wr::DebugFlags::SHOW_OVERDRAW)
552 GFX_WEBRENDER_DEBUG(".gpu-cache", wr::DebugFlags::GPU_CACHE_DBG)
553 GFX_WEBRENDER_DEBUG(".texture-cache.clear-evicted",
554 wr::DebugFlags::TEXTURE_CACHE_DBG_CLEAR_EVICTED)
555 GFX_WEBRENDER_DEBUG(".picture-caching", wr::DebugFlags::PICTURE_CACHING_DBG)
556 GFX_WEBRENDER_DEBUG(".force-picture-invalidation",
557 wr::DebugFlags::FORCE_PICTURE_INVALIDATION)
558 GFX_WEBRENDER_DEBUG(".primitives", wr::DebugFlags::PRIMITIVE_DBG)
559 // Bit 18 is for the zoom display, which requires the mouse position and thus
560 // currently only works in wrench.
561 GFX_WEBRENDER_DEBUG(".small-screen", wr::DebugFlags::SMALL_SCREEN)
562 GFX_WEBRENDER_DEBUG(".disable-opaque-pass",
563 wr::DebugFlags::DISABLE_OPAQUE_PASS)
564 GFX_WEBRENDER_DEBUG(".disable-alpha-pass", wr::DebugFlags::DISABLE_ALPHA_PASS)
565 GFX_WEBRENDER_DEBUG(".disable-clip-masks", wr::DebugFlags::DISABLE_CLIP_MASKS)
566 GFX_WEBRENDER_DEBUG(".disable-text-prims", wr::DebugFlags::DISABLE_TEXT_PRIMS)
567 GFX_WEBRENDER_DEBUG(".disable-gradient-prims",
568 wr::DebugFlags::DISABLE_GRADIENT_PRIMS)
569 GFX_WEBRENDER_DEBUG(".obscure-images", wr::DebugFlags::OBSCURE_IMAGES)
570 GFX_WEBRENDER_DEBUG(".glyph-flashing", wr::DebugFlags::GLYPH_FLASHING)
571 GFX_WEBRENDER_DEBUG(".capture-profiler", wr::DebugFlags::PROFILER_CAPTURE)
572 GFX_WEBRENDER_DEBUG(".window-visibility",
573 wr::DebugFlags::WINDOW_VISIBILITY_DBG)
574 #undef GFX_WEBRENDER_DEBUG
576 gfx::gfxVars::SetWebRenderDebugFlags(flags.bits);
579 static void WebRenderQualityPrefChangeCallback(const char* aPref, void*) {
580 gfxPlatform::GetPlatform()->UpdateForceSubpixelAAWherePossible();
583 static void WebRenderBatchingPrefChangeCallback(const char* aPrefName, void*) {
584 uint32_t count = Preferences::GetUint(
585 StaticPrefs::GetPrefName_gfx_webrender_batching_lookback(), 10);
587 gfx::gfxVars::SetWebRenderBatchingLookback(count);
590 static void WebRenderBlobTileSizePrefChangeCallback(const char* aPrefName,
591 void*) {
592 uint32_t tileSize = Preferences::GetUint(
593 StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size(), 256);
594 gfx::gfxVars::SetWebRenderBlobTileSize(tileSize);
597 static void WebRenderUploadThresholdPrefChangeCallback(const char* aPrefName,
598 void*) {
599 int value = Preferences::GetInt(
600 StaticPrefs::GetPrefName_gfx_webrender_batched_upload_threshold(),
601 512 * 512);
603 gfxVars::SetWebRenderBatchedUploadThreshold(value);
606 static uint32_t GetSkiaGlyphCacheSize() {
607 // Only increase font cache size on non-android to save memory.
608 #if !defined(MOZ_WIDGET_ANDROID)
609 // 10mb as the default pref cache size on desktop due to talos perf tweaking.
610 // Chromium uses 20mb and skia default uses 2mb.
611 // We don't need to change the font cache count since we usually
612 // cache thrash due to asian character sets in talos.
613 // Only increase memory on the content process
614 uint32_t cacheSize =
615 StaticPrefs::gfx_content_skia_font_cache_size_AtStartup() * 1024 * 1024;
616 if (mozilla::BrowserTabsRemoteAutostart()) {
617 return XRE_IsContentProcess() ? cacheSize : kDefaultGlyphCacheSize;
620 return cacheSize;
621 #else
622 return kDefaultGlyphCacheSize;
623 #endif // MOZ_WIDGET_ANDROID
626 class WebRenderMemoryReporter final : public nsIMemoryReporter {
627 public:
628 NS_DECL_ISUPPORTS
629 NS_DECL_NSIMEMORYREPORTER
631 private:
632 ~WebRenderMemoryReporter() = default;
635 // Memory reporter for WebRender.
637 // The reporting within WebRender is manual and incomplete. We could do a much
638 // more thorough job by depending on the malloc_size_of crate, but integrating
639 // that into WebRender is tricky [1].
641 // So the idea is to start with manual reporting for the large allocations
642 // detected by DMD, and see how much that can cover in practice (which may
643 // require a few rounds of iteration). If that approach turns out to be
644 // fundamentally insufficient, we can either duplicate more of the
645 // malloc_size_of functionality in WebRender, or deal with the complexity of a
646 // gecko-only crate dependency.
648 // [1] See https://bugzilla.mozilla.org/show_bug.cgi?id=1480293#c1
649 struct WebRenderMemoryReporterHelper {
650 WebRenderMemoryReporterHelper(nsIHandleReportCallback* aCallback,
651 nsISupports* aData)
652 : mCallback(aCallback), mData(aData) {}
653 nsCOMPtr<nsIHandleReportCallback> mCallback;
654 nsCOMPtr<nsISupports> mData;
656 void Report(size_t aBytes, const char* aName) const {
657 nsPrintfCString path("explicit/gfx/webrender/%s", aName);
658 nsCString desc("CPU heap memory used by WebRender"_ns);
659 ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_HEAP);
662 void ReportTexture(size_t aBytes, const char* aName) const {
663 nsPrintfCString path("gfx/webrender/textures/%s", aName);
664 nsCString desc("GPU texture memory used by WebRender"_ns);
665 ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_OTHER);
668 void ReportTotalGPUBytes(size_t aBytes) const {
669 nsCString path("gfx/webrender/total-gpu-bytes"_ns);
670 nsCString desc(nsLiteralCString(
671 "Total GPU bytes used by WebRender (should match textures/ sum)"));
672 ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_OTHER);
675 void ReportInternal(size_t aBytes, nsACString& aPath, nsACString& aDesc,
676 int32_t aKind) const {
677 // Generally, memory reporters pass the empty string as the process name to
678 // indicate "current process". However, if we're using a GPU process, the
679 // measurements will actually take place in that process, and it's easier to
680 // just note that here rather than trying to invoke the memory reporter in
681 // the GPU process.
682 nsAutoCString processName;
683 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
684 GPUParent::GetGPUProcessName(processName);
687 mCallback->Callback(processName, aPath, aKind,
688 nsIMemoryReporter::UNITS_BYTES, aBytes, aDesc, mData);
692 static void FinishAsyncMemoryReport() {
693 nsCOMPtr<nsIMemoryReporterManager> imgr =
694 do_GetService("@mozilla.org/memory-reporter-manager;1");
695 if (imgr) {
696 imgr->EndReport();
700 // clang-format off
701 // (For some reason, clang-format gets the second macro right, but totally mangles the first).
702 #define REPORT_INTERNER(id) \
703 helper.Report(aReport.interning.interners.id, \
704 "interning/" #id "/interners");
705 // clang-format on
707 #define REPORT_DATA_STORE(id) \
708 helper.Report(aReport.interning.data_stores.id, \
709 "interning/" #id "/data-stores");
711 NS_IMPL_ISUPPORTS(WebRenderMemoryReporter, nsIMemoryReporter)
713 NS_IMETHODIMP
714 WebRenderMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
715 nsISupports* aData, bool aAnonymize) {
716 MOZ_ASSERT(XRE_IsParentProcess());
717 MOZ_ASSERT(NS_IsMainThread());
718 layers::CompositorManagerChild* manager =
719 CompositorManagerChild::GetInstance();
720 if (!manager) {
721 FinishAsyncMemoryReport();
722 return NS_OK;
725 WebRenderMemoryReporterHelper helper(aHandleReport, aData);
726 manager->SendReportMemory(
727 [=](wr::MemoryReport aReport) {
728 // CPU Memory.
729 helper.Report(aReport.clip_stores, "clip-stores");
730 helper.Report(aReport.gpu_cache_metadata, "gpu-cache/metadata");
731 helper.Report(aReport.gpu_cache_cpu_mirror, "gpu-cache/cpu-mirror");
732 helper.Report(aReport.render_tasks, "render-tasks");
733 helper.Report(aReport.hit_testers, "hit-testers");
734 helper.Report(aReport.fonts, "resource-cache/fonts");
735 helper.Report(aReport.weak_fonts, "resource-cache/weak-fonts");
736 helper.Report(aReport.images, "resource-cache/images");
737 helper.Report(aReport.rasterized_blobs,
738 "resource-cache/rasterized-blobs");
739 helper.Report(aReport.texture_cache_structures,
740 "texture-cache/structures");
741 helper.Report(aReport.shader_cache, "shader-cache");
742 helper.Report(aReport.display_list, "display-list");
743 helper.Report(aReport.swgl, "swgl");
744 helper.Report(aReport.upload_staging_memory, "upload-stagin-memory");
746 WEBRENDER_FOR_EACH_INTERNER(REPORT_INTERNER);
747 WEBRENDER_FOR_EACH_INTERNER(REPORT_DATA_STORE);
749 // GPU Memory.
750 helper.ReportTexture(aReport.gpu_cache_textures, "gpu-cache");
751 helper.ReportTexture(aReport.vertex_data_textures, "vertex-data");
752 helper.ReportTexture(aReport.render_target_textures, "render-targets");
753 helper.ReportTexture(aReport.depth_target_textures, "depth-targets");
754 helper.ReportTexture(aReport.picture_tile_textures, "picture-tiles");
755 helper.ReportTexture(aReport.atlas_textures, "texture-cache/atlas");
756 helper.ReportTexture(aReport.standalone_textures,
757 "texture-cache/standalone");
758 helper.ReportTexture(aReport.texture_upload_pbos,
759 "texture-upload-pbos");
760 helper.ReportTexture(aReport.swap_chain, "swap-chains");
761 helper.ReportTexture(aReport.render_texture_hosts,
762 "render-texture-hosts");
763 helper.ReportTexture(aReport.upload_staging_textures,
764 "upload-staging-textures");
766 FinishAsyncMemoryReport();
768 [](mozilla::ipc::ResponseRejectReason&& aReason) {
769 FinishAsyncMemoryReport();
772 return NS_OK;
775 #undef REPORT_INTERNER
776 #undef REPORT_DATA_STORE
778 void gfxPlatform::Init() {
779 MOZ_RELEASE_ASSERT(!XRE_IsGPUProcess(), "GFX: Not allowed in GPU process.");
780 MOZ_RELEASE_ASSERT(!XRE_IsRDDProcess(), "GFX: Not allowed in RDD process.");
781 MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
783 if (gEverInitialized) {
784 MOZ_CRASH("Already started???");
786 gEverInitialized = true;
788 gfxVars::Initialize();
790 gfxConfig::Init();
792 if (XRE_IsParentProcess()) {
793 GPUProcessManager::Initialize();
794 RDDProcessManager::Initialize();
796 nsCOMPtr<nsIFile> file;
797 nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
798 if (NS_FAILED(rv)) {
799 gfxVars::SetGREDirectory(nsString());
800 } else {
801 nsAutoString path;
802 file->GetPath(path);
803 gfxVars::SetGREDirectory(nsString(path));
807 if (XRE_IsParentProcess()) {
808 nsCOMPtr<nsIFile> profDir;
809 nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
810 getter_AddRefs(profDir));
811 if (NS_FAILED(rv)) {
812 gfxVars::SetProfDirectory(nsString());
813 } else {
814 nsAutoString path;
815 profDir->GetPath(path);
816 gfxVars::SetProfDirectory(nsString(path));
819 nsAutoCString path;
820 Preferences::GetCString("layers.windowrecording.path", path);
821 gfxVars::SetLayersWindowRecordingPath(path);
823 if (gFxREmbedded) {
824 gfxVars::SetFxREmbedded(true);
828 // Drop a note in the crash report if we end up forcing an option that could
829 // destabilize things. New items should be appended at the end (of an
830 // existing or in a new section), so that we don't have to know the version to
831 // interpret these cryptic strings.
833 nsAutoCString forcedPrefs;
834 // D2D prefs
835 forcedPrefs.AppendPrintf(
836 "FP(D%d%d", StaticPrefs::gfx_direct2d_disabled_AtStartup(),
837 StaticPrefs::gfx_direct2d_force_enabled_AtStartup());
838 // Layers prefs
839 forcedPrefs.AppendPrintf(
840 "-L%d%d%d%d",
841 StaticPrefs::layers_amd_switchable_gfx_enabled_AtStartup(),
842 StaticPrefs::layers_acceleration_disabled_AtStartup_DoNotUseDirectly(),
843 StaticPrefs::
844 layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly(),
845 StaticPrefs::layers_d3d11_force_warp_AtStartup());
846 // WebGL prefs
847 forcedPrefs.AppendPrintf(
848 "-W%d%d%d%d%d%d%d%d", StaticPrefs::webgl_angle_force_d3d11(),
849 StaticPrefs::webgl_angle_force_warp(), StaticPrefs::webgl_disabled(),
850 StaticPrefs::webgl_disable_angle(), StaticPrefs::webgl_dxgl_enabled(),
851 StaticPrefs::webgl_force_enabled(),
852 StaticPrefs::webgl_force_layers_readback(),
853 StaticPrefs::webgl_msaa_force());
854 // Prefs that don't fit into any of the other sections
855 forcedPrefs.AppendPrintf("-T%d%d%d) ",
856 StaticPrefs::gfx_android_rgb16_force_AtStartup(),
857 StaticPrefs::gfx_canvas_accelerated(),
858 StaticPrefs::layers_force_shmem_tiles_AtStartup());
859 ScopedGfxFeatureReporter::AppNote(forcedPrefs);
862 InitMoz2DLogging();
864 /* Initialize the GfxInfo service.
865 * Note: we can't call functions on GfxInfo that depend
866 * on gPlatform until after it has been initialized
867 * below. GfxInfo initialization annotates our
868 * crash reports so we want to do it before
869 * we try to load any drivers and do device detection
870 * incase that code crashes. See bug #591561. */
871 nsCOMPtr<nsIGfxInfo> gfxInfo;
872 /* this currently will only succeed on Windows */
873 gfxInfo = components::GfxInfo::Service();
875 if (XRE_IsParentProcess()) {
876 // Some gfxVars must be initialized prior gPlatform for coherent results.
877 gfxVars::SetDXInterop2Blocked(IsDXInterop2Blocked());
878 gfxVars::SetDXNV12Blocked(IsDXNV12Blocked());
879 gfxVars::SetDXP010Blocked(IsDXP010Blocked());
880 gfxVars::SetDXP016Blocked(IsDXP016Blocked());
883 #if defined(XP_WIN)
884 gPlatform = new gfxWindowsPlatform;
885 #elif defined(XP_MACOSX)
886 gPlatform = new gfxPlatformMac;
887 #elif defined(MOZ_WIDGET_GTK)
888 gPlatform = new gfxPlatformGtk;
889 #elif defined(ANDROID)
890 gPlatform = new gfxAndroidPlatform;
891 #else
892 # error "No gfxPlatform implementation available"
893 #endif
894 gPlatform->PopulateScreenInfo();
895 gPlatform->InitAcceleration();
896 gPlatform->InitWebRenderConfig();
898 gPlatform->InitHardwareVideoConfig();
899 gPlatform->InitWebGLConfig();
900 gPlatform->InitWebGPUConfig();
901 gPlatform->InitWindowOcclusionConfig();
903 // When using WebRender, we defer initialization of the D3D11 devices until
904 // the (rare) cases where they're used. Note that the GPU process where
905 // WebRender runs doesn't initialize gfxPlatform and performs explicit
906 // initialization of the bits it needs.
907 if (!UseWebRender()
908 #if defined(XP_WIN)
909 || (UseWebRender() && XRE_IsParentProcess() &&
910 !gfxConfig::IsEnabled(Feature::GPU_PROCESS) &&
911 StaticPrefs::
912 gfx_webrender_enabled_no_gpu_process_with_angle_win_AtStartup())
913 #endif
915 gPlatform->EnsureDevicesInitialized();
918 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
919 GPUProcessManager* gpu = GPUProcessManager::Get();
920 Unused << gpu->LaunchGPUProcess();
923 if (XRE_IsParentProcess()) {
924 nsAutoCString allowlist;
925 Preferences::GetCString("gfx.offscreencanvas.domain-allowlist", allowlist);
926 gfxVars::SetOffscreenCanvasDomainAllowlist(allowlist);
928 // Create the global vsync source and dispatcher.
929 RefPtr<VsyncSource> vsyncSource =
930 gfxPlatform::ForceSoftwareVsync()
931 ? gPlatform->GetSoftwareVsyncSource()
932 : gPlatform->GetGlobalHardwareVsyncSource();
933 gPlatform->mVsyncDispatcher = new VsyncDispatcher(vsyncSource);
935 // Listen for layout.frame_rate pref changes.
936 Preferences::RegisterCallback(
937 gfxPlatform::ReInitFrameRate,
938 nsDependentCString(StaticPrefs::GetPrefName_layout_frame_rate()));
939 Preferences::RegisterCallback(
940 gfxPlatform::ReInitFrameRate,
941 nsDependentCString(
942 StaticPrefs::GetPrefName_privacy_resistFingerprinting()));
945 // Create the sRGB to output display profile transforms. They can be accessed
946 // off the main thread so we want to avoid a race condition.
947 InitializeCMS();
949 SkGraphics::Init();
950 #ifdef MOZ_ENABLE_FREETYPE
951 SkInitCairoFT(gPlatform->FontHintingEnabled());
952 #endif
954 InitLayersIPC();
956 gPlatform->mHasVariationFontSupport = gPlatform->CheckVariationFontSupport();
958 // This *create* the platform font list instance, but may not *initialize* it
959 // yet if the gfx.font-list.lazy-init.enabled pref is set. The first *use*
960 // of the list will ensure it is initialized.
961 if (!gPlatform->CreatePlatformFontList()) {
962 MOZ_CRASH("Could not initialize gfxPlatformFontList");
965 gPlatform->mScreenReferenceDrawTarget =
966 gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
967 SurfaceFormat::B8G8R8A8);
968 if (!gPlatform->mScreenReferenceDrawTarget ||
969 !gPlatform->mScreenReferenceDrawTarget->IsValid()) {
970 // If TDR is detected, create a draw target with software backend
971 // and it should be replaced later when the process gets the device
972 // reset notification.
973 if (!gPlatform->DidRenderingDeviceReset()) {
974 gfxCriticalError() << "Could not initialize mScreenReferenceDrawTarget";
978 if (NS_FAILED(gfxFontCache::Init())) {
979 MOZ_CRASH("Could not initialize gfxFontCache");
982 Preferences::RegisterPrefixCallbacks(FontPrefChanged, kObservedPrefs);
984 GLContext::PlatformStartup();
986 // Listen to memory pressure event so we can purge DrawTarget caches
987 gPlatform->mMemoryPressureObserver =
988 layers::MemoryPressureObserver::Create(gPlatform);
990 // Request the imgITools service, implicitly initializing ImageLib.
991 nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
992 if (!imgTools) {
993 MOZ_CRASH("Could not initialize ImageLib");
996 RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
997 if (XRE_IsParentProcess() && UseWebRender()) {
998 RegisterStrongAsyncMemoryReporter(new WebRenderMemoryReporter());
1001 RegisterStrongMemoryReporter(new SkMemoryReporter());
1003 uint32_t skiaCacheSize = GetSkiaGlyphCacheSize();
1004 if (skiaCacheSize != kDefaultGlyphCacheSize) {
1005 SkGraphics::SetFontCacheLimit(skiaCacheSize);
1008 InitNullMetadata();
1009 InitOpenGLConfig();
1011 if (XRE_IsParentProcess()) {
1012 Preferences::Unlock(FONT_VARIATIONS_PREF);
1013 if (!gPlatform->HasVariationFontSupport()) {
1014 // Ensure variation fonts are disabled and the pref is locked.
1015 Preferences::SetBool(FONT_VARIATIONS_PREF, false, PrefValueKind::Default);
1016 Preferences::SetBool(FONT_VARIATIONS_PREF, false);
1017 Preferences::Lock(FONT_VARIATIONS_PREF);
1021 if (XRE_IsParentProcess()) {
1022 ReportTelemetry();
1025 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
1026 if (obs) {
1027 obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr);
1031 void gfxPlatform::ReportTelemetry() {
1032 MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
1033 "GFX: Only allowed to be called from parent process.");
1035 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
1038 auto& screenManager = widget::ScreenManager::GetSingleton();
1039 const uint32_t screenCount = screenManager.CurrentScreenList().Length();
1040 RefPtr<widget::Screen> primaryScreen = screenManager.GetPrimaryScreen();
1041 const LayoutDeviceIntRect rect = primaryScreen->GetRect();
1043 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_DISPLAY_COUNT, screenCount);
1044 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_DISPLAY_PRIMARY_HEIGHT,
1045 uint32_t(rect.Height()));
1046 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_DISPLAY_PRIMARY_WIDTH,
1047 uint32_t(rect.Width()));
1050 nsString adapterDesc;
1051 gfxInfo->GetAdapterDescription(adapterDesc);
1052 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DESCRIPTION,
1053 adapterDesc);
1055 nsString adapterVendorId;
1056 gfxInfo->GetAdapterVendorID(adapterVendorId);
1057 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_VENDOR_ID,
1058 adapterVendorId);
1060 nsString adapterDeviceId;
1061 gfxInfo->GetAdapterDeviceID(adapterDeviceId);
1062 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DEVICE_ID,
1063 adapterDeviceId);
1065 nsString adapterSubsystemId;
1066 gfxInfo->GetAdapterSubsysID(adapterSubsystemId);
1067 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_SUBSYSTEM_ID,
1068 adapterSubsystemId);
1070 uint32_t adapterRam = 0;
1071 gfxInfo->GetAdapterRAM(&adapterRam);
1072 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_RAM, adapterRam);
1074 nsString adapterDriver;
1075 gfxInfo->GetAdapterDriver(adapterDriver);
1076 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DRIVER_FILES,
1077 adapterDriver);
1079 nsString adapterDriverVendor;
1080 gfxInfo->GetAdapterDriverVendor(adapterDriverVendor);
1081 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DRIVER_VENDOR,
1082 adapterDriverVendor);
1084 nsString adapterDriverVersion;
1085 gfxInfo->GetAdapterDriverVersion(adapterDriverVersion);
1086 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DRIVER_VERSION,
1087 adapterDriverVersion);
1089 nsString adapterDriverDate;
1090 gfxInfo->GetAdapterDriverDate(adapterDriverDate);
1091 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_ADAPTER_DRIVER_DATE,
1092 adapterDriverDate);
1094 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_HEADLESS, IsHeadless());
1097 static bool IsFeatureSupported(long aFeature, bool aDefault) {
1098 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
1099 nsCString blockId;
1100 int32_t status;
1101 if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, blockId, &status))) {
1102 return aDefault;
1104 return status == nsIGfxInfo::FEATURE_STATUS_OK;
1107 /* static*/
1108 bool gfxPlatform::IsDXInterop2Blocked() {
1109 return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_INTEROP2, false);
1112 /* static*/
1113 bool gfxPlatform::IsDXNV12Blocked() {
1114 return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_NV12, false);
1117 /* static*/
1118 bool gfxPlatform::IsDXP010Blocked() {
1119 return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_P010, false);
1122 /* static*/
1123 bool gfxPlatform::IsDXP016Blocked() {
1124 return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_P016, false);
1127 /* static */
1128 int32_t gfxPlatform::MaxTextureSize() {
1129 // Make sure we don't completely break rendering because of a typo in the
1130 // pref or whatnot.
1131 const int32_t kMinSizePref = 2048;
1132 return std::max(
1133 kMinSizePref,
1134 StaticPrefs::gfx_max_texture_size_AtStartup_DoNotUseDirectly());
1137 /* static */
1138 int32_t gfxPlatform::MaxAllocSize() {
1139 // Make sure we don't completely break rendering because of a typo in the
1140 // pref or whatnot.
1141 const int32_t kMinAllocPref = 10000000;
1142 return std::max(kMinAllocPref,
1143 StaticPrefs::gfx_max_alloc_size_AtStartup_DoNotUseDirectly());
1146 /* static */
1147 void gfxPlatform::InitMoz2DLogging() {
1148 auto fwd = new CrashStatsLogForwarder(
1149 CrashReporter::Annotation::GraphicsCriticalError);
1150 fwd->SetCircularBufferSize(StaticPrefs::gfx_logging_crash_length_AtStartup());
1152 mozilla::gfx::Config cfg;
1153 cfg.mLogForwarder = fwd;
1154 cfg.mMaxTextureSize = gfxPlatform::MaxTextureSize();
1155 cfg.mMaxAllocSize = gfxPlatform::MaxAllocSize();
1157 gfx::Factory::Init(cfg);
1160 /* static */
1161 bool gfxPlatform::IsHeadless() {
1162 static bool initialized = false;
1163 static bool headless = false;
1164 if (!initialized) {
1165 initialized = true;
1166 headless = PR_GetEnv("MOZ_HEADLESS");
1168 return headless;
1171 /* static */
1172 bool gfxPlatform::UseWebRender() { return gfx::gfxVars::UseWebRender(); }
1174 /* static */
1175 bool gfxPlatform::UseRemoteCanvas() {
1176 return XRE_IsContentProcess() && gfx::gfxVars::RemoteCanvasEnabled();
1179 /* static */
1180 bool gfxPlatform::IsBackendAccelerated(
1181 const mozilla::gfx::BackendType aBackendType) {
1182 return aBackendType == BackendType::DIRECT2D ||
1183 aBackendType == BackendType::DIRECT2D1_1;
1186 /* static */
1187 bool gfxPlatform::CanMigrateMacGPUs() {
1188 int32_t pMigration = StaticPrefs::gfx_compositor_gpu_migration();
1190 bool forceDisable = pMigration == 0;
1191 bool forceEnable = pMigration == 2;
1193 return forceEnable || !forceDisable;
1196 static bool sLayersIPCIsUp = false;
1198 /* static */
1199 void gfxPlatform::InitNullMetadata() {
1200 ScrollMetadata::sNullMetadata = new ScrollMetadata();
1201 ClearOnShutdown(&ScrollMetadata::sNullMetadata);
1204 void gfxPlatform::Shutdown() {
1205 // In some cases, gPlatform may not be created but Shutdown() called,
1206 // e.g., during xpcshell tests.
1207 if (!gPlatform) {
1208 return;
1211 MOZ_ASSERT(!sLayersIPCIsUp);
1213 // These may be called before the corresponding subsystems have actually
1214 // started up. That's OK, they can handle it.
1215 gfxFontCache::Shutdown();
1216 gfxGradientCache::Shutdown();
1217 gfxAlphaBoxBlur::ShutdownBlurCache();
1218 gfxGraphiteShaper::Shutdown();
1219 gfxPlatformFontList::Shutdown();
1220 gfxFontMissingGlyphs::Shutdown();
1222 // Free the various non-null transforms and loaded profiles
1223 ShutdownCMS();
1225 Preferences::UnregisterPrefixCallbacks(FontPrefChanged, kObservedPrefs);
1227 NS_ASSERTION(gPlatform->mMemoryPressureObserver,
1228 "mMemoryPressureObserver has already gone");
1229 if (gPlatform->mMemoryPressureObserver) {
1230 gPlatform->mMemoryPressureObserver->Unregister();
1231 gPlatform->mMemoryPressureObserver = nullptr;
1234 if (XRE_IsParentProcess()) {
1235 if (gPlatform->mGlobalHardwareVsyncSource) {
1236 gPlatform->mGlobalHardwareVsyncSource->Shutdown();
1238 if (gPlatform->mSoftwareVsyncSource &&
1239 gPlatform->mSoftwareVsyncSource !=
1240 gPlatform->mGlobalHardwareVsyncSource) {
1241 gPlatform->mSoftwareVsyncSource->Shutdown();
1245 gPlatform->mGlobalHardwareVsyncSource = nullptr;
1246 gPlatform->mSoftwareVsyncSource = nullptr;
1247 gPlatform->mVsyncDispatcher = nullptr;
1249 // Shut down the default GL context provider.
1250 GLContextProvider::Shutdown();
1252 #if defined(XP_WIN)
1253 // The above shutdown calls operate on the available context providers on
1254 // most platforms. Windows is a "special snowflake", though, and has three
1255 // context providers available, so we have to shut all of them down.
1256 // We should only support the default GL provider on Windows; then, this
1257 // could go away. Unfortunately, we currently support WGL (the default) for
1258 // WebGL on Optimus.
1259 GLContextProviderEGL::Shutdown();
1260 #endif
1262 if (XRE_IsParentProcess()) {
1263 GPUProcessManager::Shutdown();
1264 VRProcessManager::Shutdown();
1265 RDDProcessManager::Shutdown();
1268 gfx::Factory::ShutDown();
1269 gfxVars::Shutdown();
1270 gfxFont::DestroySingletons();
1272 gfxConfig::Shutdown();
1274 gPlatform->WillShutdown();
1276 delete gPlatform;
1277 gPlatform = nullptr;
1280 /* static */
1281 void gfxPlatform::InitLayersIPC() {
1282 if (sLayersIPCIsUp) {
1283 return;
1285 sLayersIPCIsUp = true;
1287 if (XRE_IsParentProcess()) {
1288 #if defined(XP_WIN)
1289 if (gfxConfig::IsEnabled(gfx::Feature::WINDOW_OCCLUSION)) {
1290 widget::WinWindowOcclusionTracker::Ensure();
1292 #endif
1293 if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS) && UseWebRender()) {
1294 RemoteTextureMap::Init();
1295 wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());
1296 image::ImageMemoryReporter::InitForWebRender();
1299 layers::CompositorThreadHolder::Start();
1303 /* static */
1304 void gfxPlatform::ShutdownLayersIPC() {
1305 if (!sLayersIPCIsUp) {
1306 return;
1308 sLayersIPCIsUp = false;
1310 if (XRE_IsContentProcess()) {
1311 gfx::VRManagerChild::ShutDown();
1312 gfx::CanvasManagerChild::Shutdown();
1313 // cf bug 1215265.
1314 if (StaticPrefs::layers_child_process_shutdown()) {
1315 layers::CompositorManagerChild::Shutdown();
1316 layers::ImageBridgeChild::ShutDown();
1319 } else if (XRE_IsParentProcess()) {
1320 gfx::VRManagerChild::ShutDown();
1321 gfx::CanvasManagerChild::Shutdown();
1322 layers::CompositorManagerChild::Shutdown();
1323 layers::ImageBridgeChild::ShutDown();
1324 // This could be running on either the Compositor or the Renderer thread.
1325 gfx::CanvasManagerParent::Shutdown();
1326 RemoteTextureMap::Shutdown();
1327 // This has to happen after shutting down the child protocols.
1328 layers::CompositorThreadHolder::Shutdown();
1329 image::ImageMemoryReporter::ShutdownForWebRender();
1330 // There is a case that RenderThread exists when UseWebRender() is
1331 // false. This could happen when WebRender was fallbacked to compositor.
1332 if (wr::RenderThread::Get()) {
1333 wr::RenderThread::ShutDown();
1335 Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback,
1336 WR_DEBUG_PREF);
1337 Preferences::UnregisterCallback(WebRendeProfilerUIPrefChangeCallback,
1338 "gfx.webrender.debug.profiler-ui");
1339 Preferences::UnregisterCallback(
1340 WebRenderBlobTileSizePrefChangeCallback,
1341 nsDependentCString(
1342 StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size()));
1344 #if defined(XP_WIN)
1345 widget::WinWindowOcclusionTracker::ShutDown();
1346 #endif
1347 } else {
1348 // TODO: There are other kind of processes and we should make sure gfx
1349 // stuff is either not created there or shut down properly.
1353 void gfxPlatform::WillShutdown() {
1354 // Destoy these first in case they depend on backend-specific resources.
1355 // Otherwise, the backend's destructor would be called before the
1356 // base gfxPlatform destructor.
1357 mScreenReferenceSurface = nullptr;
1358 mScreenReferenceDrawTarget = nullptr;
1360 // Always clear out the Skia font cache here, in case it is referencing any
1361 // SharedFTFaces that would otherwise outlive destruction of the FT_Library
1362 // that owns them.
1363 SkGraphics::PurgeFontCache();
1365 // The cairo folks think we should only clean up in debug builds,
1366 // but we're generally in the habit of trying to shut down as
1367 // cleanly as possible even in production code, so call this
1368 // cairo_debug_* function unconditionally.
1370 // because cairo can assert and thus crash on shutdown, don't do this in
1371 // release builds
1372 #ifdef NS_FREE_PERMANENT_DATA
1373 cairo_debug_reset_static_data();
1374 #endif
1377 gfxPlatform::~gfxPlatform() = default;
1379 /* static */
1380 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForSurface(
1381 gfxASurface* aSurface, const IntSize& aSize) {
1382 SurfaceFormat format = aSurface->GetSurfaceFormat();
1383 RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(
1384 aSurface->CairoSurface(), aSize, &format);
1385 if (!drawTarget) {
1386 gfxWarning() << "gfxPlatform::CreateDrawTargetForSurface failed in "
1387 "CreateDrawTargetForCairoSurface";
1388 return nullptr;
1390 return drawTarget.forget();
1393 cairo_user_data_key_t kSourceSurface;
1396 * Record the backend that was used to construct the SourceSurface.
1397 * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
1398 * we check to make sure the DrawTarget's backend matches the backend
1399 * for the cached SourceSurface, and only use it if they match. This
1400 * can avoid expensive and unnecessary readbacks.
1402 struct SourceSurfaceUserData {
1403 RefPtr<SourceSurface> mSrcSurface;
1404 BackendType mBackendType;
1407 static void SourceBufferDestroy(void* srcSurfUD) {
1408 delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
1411 UserDataKey kThebesSurface;
1413 struct DependentSourceSurfaceUserData {
1414 RefPtr<gfxASurface> mSurface;
1417 static void SourceSurfaceDestroyed(void* aData) {
1418 delete static_cast<DependentSourceSurfaceUserData*>(aData);
1421 void gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface* aSurface) {
1422 aSurface->SetData(&kSourceSurface, nullptr, nullptr);
1425 /* static */
1426 already_AddRefed<SourceSurface> gfxPlatform::GetSourceSurfaceForSurface(
1427 RefPtr<DrawTarget> aTarget, gfxASurface* aSurface, bool aIsPlugin) {
1428 if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
1429 return nullptr;
1432 if (!aTarget) {
1433 aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
1436 void* userData = aSurface->GetData(&kSourceSurface);
1438 if (userData) {
1439 SourceSurfaceUserData* surf = static_cast<SourceSurfaceUserData*>(userData);
1441 if (surf->mSrcSurface->IsValid() &&
1442 surf->mBackendType == aTarget->GetBackendType()) {
1443 RefPtr<SourceSurface> srcSurface(surf->mSrcSurface);
1444 return srcSurface.forget();
1446 // We can just continue here as when setting new user data the destroy
1447 // function will be called for the old user data.
1450 SurfaceFormat format = aSurface->GetSurfaceFormat();
1452 if (aTarget->GetBackendType() == BackendType::CAIRO) {
1453 // If we're going to be used with a CAIRO DrawTarget, then just create a
1454 // SourceSurfaceCairo since we don't know the underlying type of the CAIRO
1455 // DrawTarget and can't pick a better surface type. Doing this also avoids
1456 // readback of aSurface's surface into memory if, for example, aSurface
1457 // wraps an xlib cairo surface (which can be important to avoid a major
1458 // slowdown).
1460 // We return here regardless of whether CreateSourceSurfaceFromNativeSurface
1461 // succeeds or not since we don't expect to be able to do any better below
1462 // if it fails.
1464 // Note that the returned SourceSurfaceCairo holds a strong reference to
1465 // the cairo_surface_t* that it wraps, which essencially means it holds a
1466 // strong reference to aSurface since aSurface shares its
1467 // cairo_surface_t*'s reference count variable. As a result we can't cache
1468 // srcBuffer on aSurface (see below) since aSurface would then hold a
1469 // strong reference back to srcBuffer, creating a reference loop and a
1470 // memory leak. Not caching is fine since wrapping is cheap enough (no
1471 // copying) so we can just wrap again next time we're called.
1472 return Factory::CreateSourceSurfaceForCairoSurface(
1473 aSurface->CairoSurface(), aSurface->GetSize(), format);
1476 RefPtr<SourceSurface> srcBuffer;
1478 // Currently no other DrawTarget types implement
1479 // CreateSourceSurfaceFromNativeSurface
1481 if (!srcBuffer) {
1482 // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
1483 // the same data, then optimize it for aTarget:
1484 RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface);
1485 if (surf) {
1486 srcBuffer = aIsPlugin
1487 ? aTarget->OptimizeSourceSurfaceForUnknownAlpha(surf)
1488 : aTarget->OptimizeSourceSurface(surf);
1490 if (srcBuffer == surf) {
1491 // GetWrappedDataSourceSurface returns a SourceSurface that holds a
1492 // strong reference to aSurface since it wraps aSurface's data and
1493 // needs it to stay alive. As a result we can't cache srcBuffer on
1494 // aSurface (below) since aSurface would then hold a strong reference
1495 // back to srcBuffer, creating a reference loop and a memory leak. Not
1496 // caching is fine since wrapping is cheap enough (no copying) so we
1497 // can just wrap again next time we're called.
1499 // Note that the check below doesn't catch this since srcBuffer will be
1500 // a SourceSurfaceRawData object (even if aSurface is not a
1501 // gfxImageSurface object), which is why we need this separate check.
1502 return srcBuffer.forget();
1507 if (!srcBuffer) {
1508 MOZ_ASSERT(aTarget->GetBackendType() != BackendType::CAIRO,
1509 "We already tried CreateSourceSurfaceFromNativeSurface with a "
1510 "DrawTargetCairo above");
1511 // We've run out of performant options. We now try creating a SourceSurface
1512 // using a temporary DrawTargetCairo and then optimizing it to aTarget's
1513 // actual type. The CreateSourceSurfaceFromNativeSurface() call will
1514 // likely create a DataSourceSurface (possibly involving copying and/or
1515 // readback), and the OptimizeSourceSurface may well copy again and upload
1516 // to the GPU. So, while this code path is rarely hit, hitting it may be
1517 // very slow.
1518 srcBuffer = Factory::CreateSourceSurfaceForCairoSurface(
1519 aSurface->CairoSurface(), aSurface->GetSize(), format);
1520 if (srcBuffer) {
1521 srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer);
1525 if (!srcBuffer) {
1526 return nullptr;
1529 if ((srcBuffer->GetType() == SurfaceType::CAIRO &&
1530 static_cast<SourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1531 aSurface->CairoSurface()) ||
1532 (srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE &&
1533 static_cast<DataSourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1534 aSurface->CairoSurface())) {
1535 // See the "Note that the returned SourceSurfaceCairo..." comment above.
1536 return srcBuffer.forget();
1539 // Add user data to aSurface so we can cache lookups in the future.
1540 auto* srcSurfUD = new SourceSurfaceUserData;
1541 srcSurfUD->mBackendType = aTarget->GetBackendType();
1542 srcSurfUD->mSrcSurface = srcBuffer;
1543 aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
1545 return srcBuffer.forget();
1548 already_AddRefed<DataSourceSurface> gfxPlatform::GetWrappedDataSourceSurface(
1549 gfxASurface* aSurface) {
1550 RefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
1551 if (!image) {
1552 return nullptr;
1554 RefPtr<DataSourceSurface> result = Factory::CreateWrappingDataSourceSurface(
1555 image->Data(), image->Stride(), image->GetSize(),
1556 ImageFormatToSurfaceFormat(image->Format()));
1558 if (!result) {
1559 return nullptr;
1562 // If we wrapped the underlying data of aSurface, then we need to add user
1563 // data to make sure aSurface stays alive until we are done with the data.
1564 auto* srcSurfUD = new DependentSourceSurfaceUserData;
1565 srcSurfUD->mSurface = aSurface;
1566 result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
1568 return result.forget();
1571 void gfxPlatform::PopulateScreenInfo() {
1572 nsCOMPtr<nsIScreenManager> manager =
1573 do_GetService("@mozilla.org/gfx/screenmanager;1");
1574 MOZ_ASSERT(manager, "failed to get nsIScreenManager");
1576 nsCOMPtr<nsIScreen> screen;
1577 manager->GetPrimaryScreen(getter_AddRefs(screen));
1578 if (!screen) {
1579 // This can happen in xpcshell, for instance
1580 return;
1583 screen->GetColorDepth(&mScreenDepth);
1584 if (XRE_IsParentProcess()) {
1585 gfxVars::SetScreenDepth(mScreenDepth);
1588 int left, top;
1589 screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height);
1592 bool gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget) {
1593 if (!aTarget || !aTarget->IsValid()) {
1594 return false;
1597 return SupportsAzureContentForType(aTarget->GetBackendType());
1600 void gfxPlatform::PurgeSkiaFontCache() {
1601 if (gfxPlatform::GetPlatform()->GetDefaultContentBackend() ==
1602 BackendType::SKIA) {
1603 SkGraphics::PurgeFontCache();
1607 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForBackend(
1608 BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) {
1609 // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
1610 // create the best offscreen surface for the current system and situation. We
1611 // can easily take advantage of this for the Cairo backend, so that's what we
1612 // do.
1613 // mozilla::gfx::Factory can get away without having all this knowledge for
1614 // now, but this might need to change in the future (using
1615 // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
1616 // backends).
1617 if (aBackend == BackendType::CAIRO) {
1618 RefPtr<gfxASurface> surf =
1619 CreateOffscreenSurface(aSize, SurfaceFormatToImageFormat(aFormat));
1620 if (!surf || surf->CairoStatus()) {
1621 return nullptr;
1623 return CreateDrawTargetForSurface(surf, aSize);
1625 return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
1628 already_AddRefed<DrawTarget> gfxPlatform::CreateOffscreenCanvasDrawTarget(
1629 const IntSize& aSize, SurfaceFormat aFormat) {
1630 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
1632 // If we are using remote canvas we don't want to use acceleration in
1633 // canvas DrawTargets we are not remoting, so we always use the fallback
1634 // software one.
1635 if (!gfxPlatform::UseRemoteCanvas() ||
1636 !gfxPlatform::IsBackendAccelerated(mPreferredCanvasBackend)) {
1637 RefPtr<DrawTarget> target =
1638 CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
1639 if (target || mFallbackCanvasBackend == BackendType::NONE) {
1640 return target.forget();
1644 #ifdef XP_WIN
1645 // On Windows, the fallback backend (Cairo) should use its image backend.
1646 return Factory::CreateDrawTarget(mFallbackCanvasBackend, aSize, aFormat);
1647 #else
1648 return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
1649 #endif
1652 already_AddRefed<DrawTarget> gfxPlatform::CreateOffscreenContentDrawTarget(
1653 const IntSize& aSize, SurfaceFormat aFormat, bool aFallback) {
1654 BackendType backend = (aFallback) ? mSoftwareBackend : mContentBackend;
1655 NS_ASSERTION(backend != BackendType::NONE, "No backend.");
1656 RefPtr<DrawTarget> dt = CreateDrawTargetForBackend(backend, aSize, aFormat);
1658 if (!dt) {
1659 return nullptr;
1662 // We'd prefer this to take proper care and return a CaptureDT, but for the
1663 // moment since we can't and this means we're going to be drawing on the main
1664 // thread force it's initialization. See bug 1526045 and bug 1521368.
1665 dt->ClearRect(gfx::Rect());
1666 if (!dt->IsValid()) {
1667 return nullptr;
1669 return dt.forget();
1672 already_AddRefed<DrawTarget> gfxPlatform::CreateSimilarSoftwareDrawTarget(
1673 DrawTarget* aDT, const IntSize& aSize, SurfaceFormat aFormat) {
1674 RefPtr<DrawTarget> dt;
1676 if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) {
1677 dt = aDT->CreateSimilarDrawTarget(aSize, aFormat);
1678 } else {
1679 BackendType backendType = BackendType::SKIA;
1680 dt = Factory::CreateDrawTarget(backendType, aSize, aFormat);
1683 return dt.forget();
1686 /* static */
1687 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForData(
1688 unsigned char* aData, const IntSize& aSize, int32_t aStride,
1689 SurfaceFormat aFormat, bool aUninitialized) {
1690 BackendType backendType = gfxVars::ContentBackend();
1691 NS_ASSERTION(backendType != BackendType::NONE, "No backend.");
1693 if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) {
1694 backendType = BackendType::SKIA;
1697 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
1698 backendType, aData, aSize, aStride, aFormat, aUninitialized);
1700 return dt.forget();
1703 /* static */
1704 BackendType gfxPlatform::BackendTypeForName(const nsCString& aName) {
1705 if (aName.EqualsLiteral("cairo")) return BackendType::CAIRO;
1706 if (aName.EqualsLiteral("skia")) return BackendType::SKIA;
1707 if (aName.EqualsLiteral("direct2d")) return BackendType::DIRECT2D;
1708 if (aName.EqualsLiteral("direct2d1.1")) return BackendType::DIRECT2D1_1;
1709 return BackendType::NONE;
1712 nsresult gfxPlatform::GetFontList(nsAtom* aLangGroup,
1713 const nsACString& aGenericFamily,
1714 nsTArray<nsString>& aListOfFonts) {
1715 gfxPlatformFontList::PlatformFontList()->GetFontList(
1716 aLangGroup, aGenericFamily, aListOfFonts);
1717 return NS_OK;
1720 nsresult gfxPlatform::UpdateFontList(bool aFullRebuild) {
1721 gfxPlatformFontList::PlatformFontList()->UpdateFontList(aFullRebuild);
1722 return NS_OK;
1725 void gfxPlatform::GetStandardFamilyName(const nsCString& aFontName,
1726 nsACString& aFamilyName) {
1727 gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName,
1728 aFamilyName);
1731 nsAutoCString gfxPlatform::GetDefaultFontName(
1732 const nsACString& aLangGroup, const nsACString& aGenericFamily) {
1733 // To benefit from Return Value Optimization, all paths here must return
1734 // this one variable:
1735 nsAutoCString result;
1737 auto* pfl = gfxPlatformFontList::PlatformFontList();
1738 FamilyAndGeneric fam = pfl->GetDefaultFontFamily(aLangGroup, aGenericFamily);
1739 if (!pfl->GetLocalizedFamilyName(fam.mFamily, result)) {
1740 NS_WARNING("missing default font-family name");
1743 return result;
1746 bool gfxPlatform::DownloadableFontsEnabled() {
1747 if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
1748 mAllowDownloadableFonts =
1749 Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
1752 return mAllowDownloadableFonts;
1755 bool gfxPlatform::UseCmapsDuringSystemFallback() {
1756 return StaticPrefs::gfx_font_rendering_fallback_always_use_cmaps();
1759 bool gfxPlatform::OpenTypeSVGEnabled() {
1760 return StaticPrefs::gfx_font_rendering_opentype_svg_enabled();
1763 uint32_t gfxPlatform::WordCacheCharLimit() {
1764 return StaticPrefs::gfx_font_rendering_wordcache_charlimit();
1767 uint32_t gfxPlatform::WordCacheMaxEntries() {
1768 return StaticPrefs::gfx_font_rendering_wordcache_maxentries();
1771 bool gfxPlatform::UseGraphiteShaping() {
1772 return StaticPrefs::gfx_font_rendering_graphite_enabled();
1775 bool gfxPlatform::IsFontFormatSupported(uint32_t aFormatFlags) {
1776 // check for strange format flags
1777 MOZ_ASSERT(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
1778 "strange font format hint set");
1780 // accept "common" formats that we support on all platforms
1781 if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
1782 return true;
1785 // reject all other formats, known and unknown
1786 if (aFormatFlags != 0) {
1787 return false;
1790 // no format hint set, need to look at data
1791 return true;
1794 gfxFontGroup* gfxPlatform::CreateFontGroup(
1795 nsPresContext* aPresContext, const StyleFontFamilyList& aFontFamilyList,
1796 const gfxFontStyle* aStyle, nsAtom* aLanguage, bool aExplicitLanguage,
1797 gfxTextPerfMetrics* aTextPerf, gfxUserFontSet* aUserFontSet,
1798 gfxFloat aDevToCssSize) const {
1799 return new gfxFontGroup(aPresContext, aFontFamilyList, aStyle, aLanguage,
1800 aExplicitLanguage, aTextPerf, aUserFontSet,
1801 aDevToCssSize);
1804 gfxFontEntry* gfxPlatform::LookupLocalFont(nsPresContext* aPresContext,
1805 const nsACString& aFontName,
1806 WeightRange aWeightForEntry,
1807 StretchRange aStretchForEntry,
1808 SlantStyleRange aStyleForEntry) {
1809 return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(
1810 aPresContext, aFontName, aWeightForEntry, aStretchForEntry,
1811 aStyleForEntry);
1814 gfxFontEntry* gfxPlatform::MakePlatformFont(const nsACString& aFontName,
1815 WeightRange aWeightForEntry,
1816 StretchRange aStretchForEntry,
1817 SlantStyleRange aStyleForEntry,
1818 const uint8_t* aFontData,
1819 uint32_t aLength) {
1820 return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(
1821 aFontName, aWeightForEntry, aStretchForEntry, aStyleForEntry, aFontData,
1822 aLength);
1825 BackendPrefsData gfxPlatform::GetBackendPrefs() const {
1826 BackendPrefsData data;
1828 data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
1829 data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
1831 #ifdef MOZ_WIDGET_GTK
1832 data.mCanvasBitmask |= BackendTypeBit(BackendType::CAIRO);
1833 data.mContentBitmask |= BackendTypeBit(BackendType::CAIRO);
1834 #endif
1836 data.mCanvasDefault = BackendType::SKIA;
1837 data.mContentDefault = BackendType::SKIA;
1839 return data;
1842 void gfxPlatform::InitBackendPrefs(BackendPrefsData&& aPrefsData) {
1843 mPreferredCanvasBackend = GetCanvasBackendPref(aPrefsData.mCanvasBitmask);
1844 if (mPreferredCanvasBackend == BackendType::NONE) {
1845 mPreferredCanvasBackend = aPrefsData.mCanvasDefault;
1848 if (mPreferredCanvasBackend == BackendType::DIRECT2D1_1) {
1849 // Falling back to D2D 1.0 won't help us here. When D2D 1.1 DT creation
1850 // fails it means the surface was too big or there's something wrong with
1851 // the device. D2D 1.0 will encounter a similar situation.
1852 mFallbackCanvasBackend = GetCanvasBackendPref(
1853 aPrefsData.mCanvasBitmask & ~(BackendTypeBit(mPreferredCanvasBackend) |
1854 BackendTypeBit(BackendType::DIRECT2D)));
1855 } else {
1856 mFallbackCanvasBackend = GetCanvasBackendPref(
1857 aPrefsData.mCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
1860 mContentBackendBitmask = aPrefsData.mContentBitmask;
1861 mContentBackend = GetContentBackendPref(mContentBackendBitmask);
1862 if (mContentBackend == BackendType::NONE) {
1863 mContentBackend = aPrefsData.mContentDefault;
1864 // mContentBackendBitmask is our canonical reference for supported
1865 // backends so we need to add the default if we are using it and
1866 // overriding the prefs.
1867 mContentBackendBitmask |= BackendTypeBit(aPrefsData.mContentDefault);
1870 uint32_t swBackendBits = BackendTypeBit(BackendType::SKIA);
1871 #ifdef MOZ_WIDGET_GTK
1872 swBackendBits |= BackendTypeBit(BackendType::CAIRO);
1873 #endif
1874 mSoftwareBackend = GetContentBackendPref(swBackendBits);
1875 if (mSoftwareBackend == BackendType::NONE) {
1876 mSoftwareBackend = BackendType::SKIA;
1879 // If we don't have a fallback canvas backend then use the same software
1880 // fallback as content.
1881 if (mFallbackCanvasBackend == BackendType::NONE) {
1882 mFallbackCanvasBackend = mSoftwareBackend;
1885 if (XRE_IsParentProcess()) {
1886 gfxVars::SetContentBackend(mContentBackend);
1887 gfxVars::SetSoftwareBackend(mSoftwareBackend);
1891 /* static */
1892 BackendType gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask) {
1893 return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
1896 /* static */
1897 BackendType gfxPlatform::GetContentBackendPref(uint32_t& aBackendBitmask) {
1898 return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
1901 /* static */
1902 BackendType gfxPlatform::GetBackendPref(const char* aBackendPrefName,
1903 uint32_t& aBackendBitmask) {
1904 nsTArray<nsCString> backendList;
1905 nsAutoCString prefString;
1906 if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, prefString))) {
1907 ParseString(prefString, ',', backendList);
1910 uint32_t allowedBackends = 0;
1911 BackendType result = BackendType::NONE;
1912 for (uint32_t i = 0; i < backendList.Length(); ++i) {
1913 BackendType type = BackendTypeForName(backendList[i]);
1914 if (BackendTypeBit(type) & aBackendBitmask) {
1915 allowedBackends |= BackendTypeBit(type);
1916 if (result == BackendType::NONE) {
1917 result = type;
1922 aBackendBitmask = allowedBackends;
1923 return result;
1926 bool gfxPlatform::InSafeMode() {
1927 static bool sSafeModeInitialized = false;
1928 static bool sInSafeMode = false;
1930 if (!sSafeModeInitialized) {
1931 sSafeModeInitialized = true;
1932 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
1933 if (xr) {
1934 xr->GetInSafeMode(&sInSafeMode);
1937 return sInSafeMode;
1940 bool gfxPlatform::OffMainThreadCompositingEnabled() {
1941 return UsesOffMainThreadCompositing();
1944 void gfxPlatform::SetCMSModeOverride(CMSMode aMode) {
1945 MOZ_ASSERT(gCMSInitialized);
1946 gCMSMode = aMode;
1949 int gfxPlatform::GetRenderingIntent() {
1950 // StaticPrefList.yaml is using 0 as the default for the rendering
1951 // intent preference, based on that being the value for
1952 // QCMS_INTENT_DEFAULT. Assert here to catch if that ever
1953 // changes and we can then figure out what to do about it.
1954 MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
1956 /* Try to query the pref system for a rendering intent. */
1957 int32_t pIntent = StaticPrefs::gfx_color_management_rendering_intent();
1958 if ((pIntent < QCMS_INTENT_MIN) || (pIntent > QCMS_INTENT_MAX)) {
1959 /* If the pref is out of range, use embedded profile. */
1960 pIntent = -1;
1962 return pIntent;
1965 DeviceColor gfxPlatform::TransformPixel(const sRGBColor& in,
1966 qcms_transform* transform) {
1967 if (transform) {
1968 /* we want the bytes in RGB order */
1969 #ifdef IS_LITTLE_ENDIAN
1970 /* ABGR puts the bytes in |RGBA| order on little endian */
1971 uint32_t packed = in.ToABGR();
1972 qcms_transform_data(transform, (uint8_t*)&packed, (uint8_t*)&packed, 1);
1973 auto out = DeviceColor::FromABGR(packed);
1974 #else
1975 /* ARGB puts the bytes in |ARGB| order on big endian */
1976 uint32_t packed = in.UnusualToARGB();
1977 /* add one to move past the alpha byte */
1978 qcms_transform_data(transform, (uint8_t*)&packed + 1, (uint8_t*)&packed + 1,
1980 auto out = DeviceColor::UnusualFromARGB(packed);
1981 #endif
1982 out.a = in.a;
1983 return out;
1985 return DeviceColor(in.r, in.g, in.b, in.a);
1988 nsTArray<uint8_t> gfxPlatform::GetPlatformCMSOutputProfileData() {
1989 return GetPrefCMSOutputProfileData();
1992 nsTArray<uint8_t> gfxPlatform::GetPrefCMSOutputProfileData() {
1993 nsAutoCString fname;
1994 Preferences::GetCString("gfx.color_management.display_profile", fname);
1996 if (fname.IsEmpty()) {
1997 return nsTArray<uint8_t>();
2000 void* mem = nullptr;
2001 size_t size = 0;
2002 qcms_data_from_path(fname.get(), &mem, &size);
2004 nsTArray<uint8_t> result;
2006 if (mem) {
2007 result.AppendElements(static_cast<uint8_t*>(mem), size);
2008 free(mem);
2011 return result;
2014 const mozilla::gfx::ContentDeviceData* gfxPlatform::GetInitContentDeviceData() {
2015 return gContentDeviceInitData;
2018 CMSMode GfxColorManagementMode() {
2019 const auto mode = StaticPrefs::gfx_color_management_mode();
2020 if (mode >= 0 && mode < UnderlyingValue(CMSMode::AllCount)) {
2021 return CMSMode(mode);
2023 return CMSMode::Off;
2026 void gfxPlatform::InitializeCMS() {
2027 if (gCMSInitialized) {
2028 return;
2031 if (XRE_IsGPUProcess()) {
2032 // Colors in the GPU process should already be managed, so we don't need to
2033 // perform color management there.
2034 gCMSInitialized = true;
2035 return;
2038 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
2039 "CMS should be initialized on the main thread");
2040 if (MOZ_UNLIKELY(!NS_IsMainThread())) {
2041 return;
2044 gCMSMode = GfxColorManagementMode();
2046 gCMSsRGBProfile = qcms_profile_sRGB();
2048 /* Determine if we're using the internal override to force sRGB as
2049 an output profile for reftests. See Bug 452125.
2051 Note that we don't normally (outside of tests) set a default value
2052 of this preference, which means nsIPrefBranch::GetBoolPref will
2053 typically throw (and leave its out-param untouched).
2055 if (StaticPrefs::gfx_color_management_force_srgb() ||
2056 StaticPrefs::gfx_color_management_native_srgb()) {
2057 gCMSOutputProfile = gCMSsRGBProfile;
2060 if (!gCMSOutputProfile) {
2061 nsTArray<uint8_t> outputProfileData =
2062 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfileData();
2063 if (!outputProfileData.IsEmpty()) {
2064 gCMSOutputProfile = qcms_profile_from_memory(outputProfileData.Elements(),
2065 outputProfileData.Length());
2069 /* Determine if the profile looks bogus. If so, close the profile
2070 * and use sRGB instead. See bug 460629, */
2071 if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
2072 NS_ASSERTION(gCMSOutputProfile != gCMSsRGBProfile,
2073 "Builtin sRGB profile tagged as bogus!!!");
2074 qcms_profile_release(gCMSOutputProfile);
2075 gCMSOutputProfile = nullptr;
2078 if (!gCMSOutputProfile) {
2079 gCMSOutputProfile = gCMSsRGBProfile;
2082 /* Precache the LUT16 Interpolations for the output profile. See
2083 bug 444661 for details. */
2084 qcms_profile_precache_output_transform(gCMSOutputProfile);
2086 // Create the RGB transform.
2087 gCMSRGBTransform =
2088 qcms_transform_create(gCMSsRGBProfile, QCMS_DATA_RGB_8, gCMSOutputProfile,
2089 QCMS_DATA_RGB_8, QCMS_INTENT_PERCEPTUAL);
2091 // And the inverse.
2092 gCMSInverseRGBTransform =
2093 qcms_transform_create(gCMSOutputProfile, QCMS_DATA_RGB_8, gCMSsRGBProfile,
2094 QCMS_DATA_RGB_8, QCMS_INTENT_PERCEPTUAL);
2096 // The RGBA transform.
2097 gCMSRGBATransform = qcms_transform_create(gCMSsRGBProfile, QCMS_DATA_RGBA_8,
2098 gCMSOutputProfile, QCMS_DATA_RGBA_8,
2099 QCMS_INTENT_PERCEPTUAL);
2101 // And the BGRA one.
2102 gCMSBGRATransform = qcms_transform_create(gCMSsRGBProfile, QCMS_DATA_BGRA_8,
2103 gCMSOutputProfile, QCMS_DATA_BGRA_8,
2104 QCMS_INTENT_PERCEPTUAL);
2106 // FIXME: We only enable iccv4 after we create the platform profile, to
2107 // wallpaper over bug 1697787.
2109 // This should happen ideally right after setting gCMSMode.
2110 if (StaticPrefs::gfx_color_management_enablev4()) {
2111 qcms_enable_iccv4();
2114 gCMSInitialized = true;
2117 qcms_transform* gfxPlatform::GetCMSOSRGBATransform() {
2118 switch (SurfaceFormat::OS_RGBA) {
2119 case SurfaceFormat::B8G8R8A8:
2120 return GetCMSBGRATransform();
2121 case SurfaceFormat::R8G8B8A8:
2122 return GetCMSRGBATransform();
2123 default:
2124 // We do not support color management with big endian.
2125 return nullptr;
2129 qcms_data_type gfxPlatform::GetCMSOSRGBAType() {
2130 switch (SurfaceFormat::OS_RGBA) {
2131 case SurfaceFormat::B8G8R8A8:
2132 return QCMS_DATA_BGRA_8;
2133 case SurfaceFormat::R8G8B8A8:
2134 return QCMS_DATA_RGBA_8;
2135 default:
2136 // We do not support color management with big endian.
2137 return QCMS_DATA_RGBA_8;
2141 /* Shuts down various transforms and profiles for CMS. */
2142 void gfxPlatform::ShutdownCMS() {
2143 if (gCMSRGBTransform) {
2144 qcms_transform_release(gCMSRGBTransform);
2145 gCMSRGBTransform = nullptr;
2147 if (gCMSInverseRGBTransform) {
2148 qcms_transform_release(gCMSInverseRGBTransform);
2149 gCMSInverseRGBTransform = nullptr;
2151 if (gCMSRGBATransform) {
2152 qcms_transform_release(gCMSRGBATransform);
2153 gCMSRGBATransform = nullptr;
2155 if (gCMSBGRATransform) {
2156 qcms_transform_release(gCMSBGRATransform);
2157 gCMSBGRATransform = nullptr;
2159 if (gCMSOutputProfile) {
2160 qcms_profile_release(gCMSOutputProfile);
2162 // handle the aliased case
2163 if (gCMSsRGBProfile == gCMSOutputProfile) {
2164 gCMSsRGBProfile = nullptr;
2166 gCMSOutputProfile = nullptr;
2168 if (gCMSsRGBProfile) {
2169 qcms_profile_release(gCMSsRGBProfile);
2170 gCMSsRGBProfile = nullptr;
2173 // Reset the state variables
2174 gCMSMode = CMSMode::Off;
2175 gCMSInitialized = false;
2178 uint32_t gfxPlatform::GetBidiNumeralOption() {
2179 return StaticPrefs::bidi_numeral();
2182 /* static */
2183 void gfxPlatform::FlushFontAndWordCaches() {
2184 gfxFontCache* fontCache = gfxFontCache::GetCache();
2185 if (fontCache) {
2186 fontCache->Flush();
2189 gfxPlatform::PurgeSkiaFontCache();
2192 /* static */
2193 void gfxPlatform::ForceGlobalReflow(NeedsReframe aNeedsReframe,
2194 BroadcastToChildren aBroadcastToChildren) {
2195 MOZ_ASSERT(NS_IsMainThread());
2196 const bool reframe = aNeedsReframe == NeedsReframe::Yes;
2197 // Send a notification that will be observed by PresShells in this process
2198 // only.
2199 if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
2200 char16_t needsReframe[] = {char16_t(reframe), 0};
2201 obs->NotifyObservers(nullptr, "font-info-updated", needsReframe);
2203 if (XRE_IsParentProcess() &&
2204 aBroadcastToChildren == BroadcastToChildren::Yes) {
2205 // Propagate the change to child processes.
2206 for (auto* process :
2207 dom::ContentParent::AllProcesses(dom::ContentParent::eLive)) {
2208 Unused << process->SendForceGlobalReflow(reframe);
2213 void gfxPlatform::FontsPrefsChanged(const char* aPref) {
2214 NS_ASSERTION(aPref != nullptr, "null preference");
2215 if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
2216 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
2217 } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref) ||
2218 !strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref) ||
2219 !strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
2220 FlushFontAndWordCaches();
2221 } else if (
2222 #if defined(XP_MACOSX)
2223 !strcmp(GFX_PREF_CORETEXT_SHAPING, aPref) ||
2224 #endif
2225 !strcmp("gfx.font_rendering.ahem_antialias_none", aPref)) {
2226 FlushFontAndWordCaches();
2227 } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
2228 gfxFontCache::GetCache()->AgeAllGenerations();
2229 gfxFontCache::GetCache()->NotifyGlyphsChanged();
2233 mozilla::LogModule* gfxPlatform::GetLog(eGfxLog aWhichLog) {
2234 // logs shared across gfx
2235 static LazyLogModule sFontlistLog("fontlist");
2236 static LazyLogModule sFontInitLog("fontinit");
2237 static LazyLogModule sTextrunLog("textrun");
2238 static LazyLogModule sTextrunuiLog("textrunui");
2239 static LazyLogModule sCmapDataLog("cmapdata");
2240 static LazyLogModule sTextPerfLog("textperf");
2242 switch (aWhichLog) {
2243 case eGfxLog_fontlist:
2244 return sFontlistLog;
2245 case eGfxLog_fontinit:
2246 return sFontInitLog;
2247 case eGfxLog_textrun:
2248 return sTextrunLog;
2249 case eGfxLog_textrunui:
2250 return sTextrunuiLog;
2251 case eGfxLog_cmapdata:
2252 return sCmapDataLog;
2253 case eGfxLog_textperf:
2254 return sTextPerfLog;
2257 MOZ_ASSERT_UNREACHABLE("Unexpected log type");
2258 return nullptr;
2261 RefPtr<mozilla::gfx::DrawTarget> gfxPlatform::ScreenReferenceDrawTarget() {
2262 return (mScreenReferenceDrawTarget)
2263 ? mScreenReferenceDrawTarget
2264 : gPlatform->CreateOffscreenContentDrawTarget(
2265 IntSize(1, 1), SurfaceFormat::B8G8R8A8, true);
2268 mozilla::gfx::SurfaceFormat gfxPlatform::Optimal2DFormatForContent(
2269 gfxContentType aContent) {
2270 switch (aContent) {
2271 case gfxContentType::COLOR:
2272 switch (GetOffscreenFormat()) {
2273 case SurfaceFormat::A8R8G8B8_UINT32:
2274 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2275 case SurfaceFormat::X8R8G8B8_UINT32:
2276 return mozilla::gfx::SurfaceFormat::B8G8R8X8;
2277 case SurfaceFormat::R5G6B5_UINT16:
2278 return mozilla::gfx::SurfaceFormat::R5G6B5_UINT16;
2279 default:
2280 MOZ_ASSERT_UNREACHABLE(
2281 "unknown gfxImageFormat for "
2282 "gfxContentType::COLOR");
2283 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2285 case gfxContentType::ALPHA:
2286 return mozilla::gfx::SurfaceFormat::A8;
2287 case gfxContentType::COLOR_ALPHA:
2288 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2289 default:
2290 MOZ_ASSERT_UNREACHABLE("unknown gfxContentType");
2291 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2295 gfxImageFormat gfxPlatform::OptimalFormatForContent(gfxContentType aContent) {
2296 switch (aContent) {
2297 case gfxContentType::COLOR:
2298 return GetOffscreenFormat();
2299 case gfxContentType::ALPHA:
2300 return SurfaceFormat::A8;
2301 case gfxContentType::COLOR_ALPHA:
2302 return SurfaceFormat::A8R8G8B8_UINT32;
2303 default:
2304 MOZ_ASSERT_UNREACHABLE("unknown gfxContentType");
2305 return SurfaceFormat::A8R8G8B8_UINT32;
2310 * There are a number of layers acceleration (or layers in general) preferences
2311 * that should be consistent for the lifetime of the application (bug 840967).
2312 * As such, we will evaluate them all as soon as one of them is evaluated
2313 * and remember the values. Changing these preferences during the run will
2314 * not have any effect until we restart.
2316 static mozilla::Atomic<bool> sLayersSupportsHardwareVideoDecoding(false);
2317 static bool sLayersHardwareVideoDecodingFailed = false;
2319 static mozilla::Atomic<bool> sLayersAccelerationPrefsInitialized(false);
2321 static void VideoDecodingFailedChangedCallback(const char* aPref, void*) {
2322 sLayersHardwareVideoDecodingFailed = Preferences::GetBool(aPref, false);
2323 gfxPlatform::GetPlatform()->UpdateCanUseHardwareVideoDecoding();
2326 void gfxPlatform::UpdateCanUseHardwareVideoDecoding() {
2327 if (XRE_IsParentProcess()) {
2328 gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding());
2332 void gfxPlatform::UpdateForceSubpixelAAWherePossible() {
2333 bool forceSubpixelAAWherePossible =
2334 StaticPrefs::gfx_webrender_quality_force_subpixel_aa_where_possible();
2335 gfxVars::SetForceSubpixelAAWherePossible(forceSubpixelAAWherePossible);
2338 void gfxPlatform::InitAcceleration() {
2339 if (sLayersAccelerationPrefsInitialized) {
2340 return;
2343 InitCompositorAccelerationPrefs();
2345 // If this is called for the first time on a non-main thread, we're screwed.
2346 // At the moment there's no explicit guarantee that the main thread calls
2347 // this before the compositor thread, but let's at least make the assumption
2348 // explicit.
2349 MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
2351 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
2352 nsCString discardFailureId;
2353 int32_t status;
2355 if (XRE_IsParentProcess()) {
2356 gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
2357 gfxVars::SetOffscreenFormat(GetOffscreenFormat());
2358 gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL(
2359 RequiresAcceleratedGLContextForCompositorOGL());
2360 #ifdef XP_WIN
2361 if (NS_SUCCEEDED(
2362 gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX,
2363 discardFailureId, &status))) {
2364 gfxVars::SetAllowD3D11KeyedMutex(status == nsIGfxInfo::FEATURE_STATUS_OK);
2365 } else {
2366 // If we couldn't properly evaluate the status, err on the side
2367 // of caution and give this functionality to the user.
2368 gfxCriticalNote << "Cannot evaluate keyed mutex feature status";
2369 gfxVars::SetAllowD3D11KeyedMutex(true);
2371 if (StaticPrefs::gfx_direct3d11_use_double_buffering() &&
2372 IsWin10OrLater()) {
2373 gfxVars::SetUseDoubleBufferingWithCompositor(true);
2375 #endif
2378 if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) &&
2379 #ifdef XP_WIN
2380 Preferences::GetBool("media.wmf.dxva.enabled", true) &&
2381 #endif
2382 NS_SUCCEEDED(
2383 gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING,
2384 discardFailureId, &status))) {
2385 if (status == nsIGfxInfo::FEATURE_STATUS_OK ||
2386 #ifdef MOZ_WAYLAND
2387 StaticPrefs::media_ffmpeg_vaapi_enabled() ||
2388 #endif
2389 StaticPrefs::media_hardware_video_decoding_force_enabled_AtStartup()) {
2390 sLayersSupportsHardwareVideoDecoding = true;
2394 #ifdef MOZ_WAYLAND
2395 sLayersSupportsHardwareVideoDecoding =
2396 gfxPlatformGtk::GetPlatform()->InitVAAPIConfig(
2397 sLayersSupportsHardwareVideoDecoding);
2398 #endif
2400 sLayersAccelerationPrefsInitialized = true;
2402 if (XRE_IsParentProcess()) {
2403 Preferences::RegisterCallbackAndCall(
2404 VideoDecodingFailedChangedCallback,
2405 "media.hardware-video-decoding.failed");
2406 InitGPUProcessPrefs();
2408 gfxVars::SetRemoteCanvasEnabled(StaticPrefs::gfx_canvas_remote() &&
2409 gfxConfig::IsEnabled(Feature::GPU_PROCESS));
2413 void gfxPlatform::InitGPUProcessPrefs() {
2414 // We want to hide this from about:support, so only set a default if the
2415 // pref is known to be true.
2416 if (!StaticPrefs::layers_gpu_process_enabled_AtStartup() &&
2417 !StaticPrefs::layers_gpu_process_force_enabled_AtStartup()) {
2418 return;
2421 FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
2423 // We require E10S - otherwise, there is very little benefit to the GPU
2424 // process, since the UI process must still use acceleration for
2425 // performance.
2426 if (!BrowserTabsRemoteAutostart()) {
2427 gpuProc.DisableByDefault(FeatureStatus::Unavailable,
2428 "Multi-process mode is not enabled",
2429 "FEATURE_FAILURE_NO_E10S"_ns);
2430 } else {
2431 gpuProc.SetDefaultFromPref(
2432 StaticPrefs::GetPrefName_layers_gpu_process_enabled(), true,
2433 StaticPrefs::GetPrefDefault_layers_gpu_process_enabled());
2436 if (StaticPrefs::layers_gpu_process_force_enabled_AtStartup()) {
2437 gpuProc.UserForceEnable("User force-enabled via pref");
2440 nsCString message;
2441 nsCString failureId;
2442 if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_GPU_PROCESS,
2443 &message, failureId)) {
2444 gpuProc.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
2445 return;
2448 if (IsHeadless()) {
2449 gpuProc.ForceDisable(FeatureStatus::Blocked, "Headless mode is enabled",
2450 "FEATURE_FAILURE_HEADLESS_MODE"_ns);
2451 return;
2453 if (InSafeMode()) {
2454 gpuProc.ForceDisable(FeatureStatus::Blocked, "Safe-mode is enabled",
2455 "FEATURE_FAILURE_SAFE_MODE"_ns);
2456 return;
2459 InitPlatformGPUProcessPrefs();
2462 void gfxPlatform::InitCompositorAccelerationPrefs() {
2463 const char* acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
2465 FeatureState& feature = gfxConfig::GetFeature(Feature::HW_COMPOSITING);
2467 // Base value - does the platform allow acceleration?
2468 if (feature.SetDefault(AccelerateLayersByDefault(), FeatureStatus::Blocked,
2469 "Acceleration blocked by platform")) {
2470 if (StaticPrefs::
2471 layers_acceleration_disabled_AtStartup_DoNotUseDirectly()) {
2472 feature.UserDisable("Disabled by layers.acceleration.disabled=true",
2473 "FEATURE_FAILURE_COMP_PREF"_ns);
2474 } else if (acceleratedEnv && *acceleratedEnv == '0') {
2475 feature.UserDisable("Disabled by envvar", "FEATURE_FAILURE_COMP_ENV"_ns);
2477 } else {
2478 if (acceleratedEnv && *acceleratedEnv == '1') {
2479 feature.UserEnable("Enabled by envvar");
2483 // This has specific meaning elsewhere, so we always record it.
2484 if (StaticPrefs::
2485 layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly()) {
2486 feature.UserForceEnable("Force-enabled by pref");
2489 // Safe, headless, and record/replay modes override everything.
2490 if (InSafeMode()) {
2491 feature.ForceDisable(FeatureStatus::Blocked,
2492 "Acceleration blocked by safe-mode",
2493 "FEATURE_FAILURE_COMP_SAFEMODE"_ns);
2495 if (IsHeadless()) {
2496 feature.ForceDisable(FeatureStatus::Blocked,
2497 "Acceleration blocked by headless mode",
2498 "FEATURE_FAILURE_COMP_HEADLESSMODE"_ns);
2502 /*static*/
2503 bool gfxPlatform::WebRenderPrefEnabled() {
2504 return StaticPrefs::gfx_webrender_all_AtStartup() ||
2505 StaticPrefs::gfx_webrender_enabled_AtStartup_DoNotUseDirectly();
2508 /*static*/
2509 bool gfxPlatform::WebRenderEnvvarEnabled() {
2510 const char* env = PR_GetEnv("MOZ_WEBRENDER");
2511 return (env && *env == '1');
2514 /* static */ const char* gfxPlatform::WebRenderResourcePathOverride() {
2515 const char* resourcePath = PR_GetEnv("WR_RESOURCE_PATH");
2516 if (!resourcePath || resourcePath[0] == '\0') {
2517 return nullptr;
2519 return resourcePath;
2522 void gfxPlatform::InitWebRenderConfig() {
2523 bool prefEnabled = WebRenderPrefEnabled();
2524 bool envvarEnabled = WebRenderEnvvarEnabled();
2526 // WR? WR+ => means WR was enabled via gfx.webrender.all.qualified on
2527 // qualified hardware
2528 // WR! WR+ => means WR was enabled via gfx.webrender.{all,enabled} or
2529 // envvar, possibly on unqualified hardware
2530 // In all cases WR- means WR was not enabled, for one of many possible
2531 // reasons. Prior to bug 1523788 landing the gfx.webrender.{all,enabled}
2532 // prefs only worked on Nightly so keep that in mind when looking at older
2533 // crash reports.
2534 ScopedGfxFeatureReporter reporter("WR", prefEnabled || envvarEnabled);
2535 if (!XRE_IsParentProcess()) {
2536 // The parent process runs through all the real decision-making code
2537 // later in this function. For other processes we still want to report
2538 // the state of the feature for crash reports.
2539 if (gfxVars::UseWebRender()) {
2540 reporter.SetSuccessful();
2542 return;
2545 // Update the gfxConfig feature states.
2546 gfxConfigManager manager;
2547 manager.Init();
2548 manager.ConfigureWebRender();
2550 bool hasHardware = gfxConfig::IsEnabled(Feature::WEBRENDER);
2551 bool hasSoftware = gfxConfig::IsEnabled(Feature::WEBRENDER_SOFTWARE);
2552 bool hasWebRender = hasHardware || hasSoftware;
2554 #ifdef MOZ_WIDGET_GTK
2555 // We require a hardware driver to back the GL context unless the user forced
2556 // on WebRender.
2557 if (!gfxConfig::IsForcedOnByUser(Feature::WEBRENDER) &&
2558 StaticPrefs::gfx_webrender_reject_software_driver_AtStartup()) {
2559 gfxVars::SetWebRenderRequiresHardwareDriver(true);
2561 #endif
2563 #ifdef XP_WIN
2564 if (gfxConfig::IsEnabled(Feature::WEBRENDER_ANGLE)) {
2565 gfxVars::SetUseWebRenderANGLE(hasWebRender);
2567 #endif
2569 if (gfxConfig::IsEnabled(Feature::WEBRENDER_SHADER_CACHE)) {
2570 gfxVars::SetUseWebRenderProgramBinaryDisk(hasWebRender);
2573 gfxVars::SetUseWebRenderOptimizedShaders(
2574 gfxConfig::IsEnabled(Feature::WEBRENDER_OPTIMIZED_SHADERS));
2576 gfxVars::SetUseSoftwareWebRender(!hasHardware && hasSoftware);
2578 Preferences::RegisterPrefixCallbackAndCall(SwapIntervalPrefChangeCallback,
2579 "gfx.swap-interval");
2581 // gfxFeature is not usable in the GPU process, so we use gfxVars to transmit
2582 // this feature
2583 if (hasWebRender) {
2584 gfxVars::SetUseWebRender(true);
2585 reporter.SetSuccessful();
2587 Preferences::RegisterPrefixCallbackAndCall(WebRenderDebugPrefChangeCallback,
2588 WR_DEBUG_PREF);
2590 RegisterWebRenderBoolParamCallback();
2592 Preferences::RegisterPrefixCallbackAndCall(
2593 WebRendeProfilerUIPrefChangeCallback,
2594 "gfx.webrender.debug.profiler-ui");
2595 Preferences::RegisterCallback(
2596 WebRenderQualityPrefChangeCallback,
2597 nsDependentCString(
2598 StaticPrefs::
2599 GetPrefName_gfx_webrender_quality_force_subpixel_aa_where_possible()));
2601 Preferences::RegisterCallback(
2602 WebRenderBatchingPrefChangeCallback,
2603 nsDependentCString(
2604 StaticPrefs::GetPrefName_gfx_webrender_batching_lookback()));
2606 Preferences::RegisterCallbackAndCall(
2607 WebRenderBlobTileSizePrefChangeCallback,
2608 nsDependentCString(
2609 StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size()));
2611 Preferences::RegisterCallbackAndCall(
2612 WebRenderUploadThresholdPrefChangeCallback,
2613 nsDependentCString(
2614 StaticPrefs::GetPrefName_gfx_webrender_batched_upload_threshold()));
2616 if (WebRenderResourcePathOverride()) {
2617 CrashReporter::AnnotateCrashReport(
2618 CrashReporter::Annotation::IsWebRenderResourcePathOverridden, true);
2621 UpdateForceSubpixelAAWherePossible();
2624 #ifdef XP_WIN
2625 if (gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT)) {
2626 gfxVars::SetUseWebRenderDCompWin(true);
2628 if (StaticPrefs::gfx_webrender_software_d3d11_AtStartup()) {
2629 gfxVars::SetAllowSoftwareWebRenderD3D11(true);
2632 bool useVideoOverlay = false;
2633 if (StaticPrefs::gfx_webrender_dcomp_video_overlay_win_AtStartup()) {
2634 if (IsWin10AnniversaryUpdateOrLater() &&
2635 gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) {
2636 MOZ_ASSERT(gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT));
2637 useVideoOverlay = true;
2640 if (useVideoOverlay &&
2641 !StaticPrefs::
2642 gfx_webrender_dcomp_video_overlay_win_force_enabled_AtStartup()) {
2643 nsCString failureId;
2644 int32_t status;
2645 const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
2646 if (NS_FAILED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_VIDEO_OVERLAY,
2647 failureId, &status))) {
2648 FeatureState& feature = gfxConfig::GetFeature(Feature::VIDEO_OVERLAY);
2649 feature.DisableByDefault(FeatureStatus::BlockedNoGfxInfo,
2650 "gfxInfo is broken",
2651 "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
2652 useVideoOverlay = false;
2653 } else {
2654 if (status != nsIGfxInfo::FEATURE_ALLOW_ALWAYS) {
2655 FeatureState& feature = gfxConfig::GetFeature(Feature::VIDEO_OVERLAY);
2656 feature.DisableByDefault(FeatureStatus::Blocked,
2657 "Blocklisted by gfxInfo", failureId);
2658 useVideoOverlay = false;
2664 if (useVideoOverlay) {
2665 FeatureState& feature = gfxConfig::GetFeature(Feature::VIDEO_OVERLAY);
2666 feature.EnableByDefault();
2667 gfxVars::SetUseWebRenderDCompVideoOverlayWin(true);
2670 bool useHwVideoZeroCopy = false;
2671 if (StaticPrefs::media_wmf_zero_copy_nv12_textures_AtStartup()) {
2672 // XXX relax limitation to Windows 8.1
2673 if (IsWin10OrLater() && hasHardware) {
2674 useHwVideoZeroCopy = true;
2677 if (useHwVideoZeroCopy &&
2678 !StaticPrefs::
2679 media_wmf_zero_copy_nv12_textures_force_enabled_AtStartup()) {
2680 nsCString failureId;
2681 int32_t status;
2682 const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
2683 if (NS_FAILED(gfxInfo->GetFeatureStatus(
2684 nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY, failureId,
2685 &status))) {
2686 FeatureState& feature =
2687 gfxConfig::GetFeature(Feature::HW_DECODED_VIDEO_ZERO_COPY);
2688 feature.DisableByDefault(FeatureStatus::BlockedNoGfxInfo,
2689 "gfxInfo is broken",
2690 "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
2691 useHwVideoZeroCopy = false;
2692 } else {
2693 if (status != nsIGfxInfo::FEATURE_ALLOW_ALWAYS) {
2694 FeatureState& feature =
2695 gfxConfig::GetFeature(Feature::HW_DECODED_VIDEO_ZERO_COPY);
2696 feature.DisableByDefault(FeatureStatus::Blocked,
2697 "Blocklisted by gfxInfo", failureId);
2698 useHwVideoZeroCopy = false;
2704 if (useHwVideoZeroCopy) {
2705 FeatureState& feature =
2706 gfxConfig::GetFeature(Feature::HW_DECODED_VIDEO_ZERO_COPY);
2707 feature.EnableByDefault();
2708 gfxVars::SetHwDecodedVideoZeroCopy(true);
2711 bool reuseDecoderDevice = false;
2712 if (StaticPrefs::gfx_direct3d11_reuse_decoder_device_AtStartup()) {
2713 reuseDecoderDevice = true;
2715 if (reuseDecoderDevice &&
2716 !StaticPrefs::
2717 gfx_direct3d11_reuse_decoder_device_force_enabled_AtStartup()) {
2718 nsCString failureId;
2719 int32_t status;
2720 const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
2721 if (NS_FAILED(gfxInfo->GetFeatureStatus(
2722 nsIGfxInfo::FEATURE_REUSE_DECODER_DEVICE, failureId, &status))) {
2723 FeatureState& feature =
2724 gfxConfig::GetFeature(Feature::REUSE_DECODER_DEVICE);
2725 feature.DisableByDefault(FeatureStatus::BlockedNoGfxInfo,
2726 "gfxInfo is broken",
2727 "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
2728 reuseDecoderDevice = false;
2729 } else {
2730 if (status != nsIGfxInfo::FEATURE_ALLOW_ALWAYS) {
2731 FeatureState& feature =
2732 gfxConfig::GetFeature(Feature::REUSE_DECODER_DEVICE);
2733 feature.DisableByDefault(FeatureStatus::Blocked,
2734 "Blocklisted by gfxInfo", failureId);
2735 reuseDecoderDevice = false;
2741 if (reuseDecoderDevice) {
2742 FeatureState& feature =
2743 gfxConfig::GetFeature(Feature::REUSE_DECODER_DEVICE);
2744 feature.EnableByDefault();
2745 gfxVars::SetReuseDecoderDevice(true);
2748 if (Preferences::GetBool("gfx.webrender.flip-sequential", false)) {
2749 if (UseWebRender() && gfxVars::UseWebRenderANGLE()) {
2750 gfxVars::SetUseWebRenderFlipSequentialWin(true);
2753 if (Preferences::GetBool("gfx.webrender.triple-buffering.enabled", false)) {
2754 if (gfxVars::UseWebRenderDCompWin() ||
2755 gfxVars::UseWebRenderFlipSequentialWin()) {
2756 gfxVars::SetUseWebRenderTripleBufferingWin(true);
2759 #endif
2761 if (gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) {
2762 gfxVars::SetUseWebRenderCompositor(true);
2765 Telemetry::ScalarSet(
2766 Telemetry::ScalarID::GFX_OS_COMPOSITOR,
2767 gfx::gfxConfig::IsEnabled(gfx::Feature::WEBRENDER_COMPOSITOR));
2769 if (gfxConfig::IsEnabled(Feature::WEBRENDER_PARTIAL)) {
2770 gfxVars::SetWebRenderMaxPartialPresentRects(
2771 StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup());
2774 // Set features that affect WR's RendererOptions
2775 gfxVars::SetUseGLSwizzle(
2776 IsFeatureSupported(nsIGfxInfo::FEATURE_GL_SWIZZLE, true));
2777 gfxVars::SetUseWebRenderScissoredCacheClears(IsFeatureSupported(
2778 nsIGfxInfo::FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS, true));
2780 // The RemoveShaderCacheFromDiskIfNecessary() needs to be called after
2781 // WebRenderConfig initialization.
2782 gfxUtils::RemoveShaderCacheFromDiskIfNecessary();
2785 void gfxPlatform::InitHardwareVideoConfig() {
2786 if (!XRE_IsParentProcess()) {
2787 return;
2790 nsCString message;
2791 nsCString failureId;
2793 FeatureState& featureVP8 = gfxConfig::GetFeature(Feature::VP8_HW_DECODE);
2794 #ifndef MOZ_WIDGET_GTK
2795 featureVP8.EnableByDefault();
2796 #endif
2798 if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_VP8_HW_DECODE, &message,
2799 failureId)) {
2800 featureVP8.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
2803 gfxVars::SetUseVP8HwDecode(featureVP8.IsEnabled());
2805 FeatureState& featureVP9 = gfxConfig::GetFeature(Feature::VP9_HW_DECODE);
2806 #ifndef MOZ_WIDGET_GTK
2807 featureVP9.EnableByDefault();
2808 #endif
2809 if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_VP9_HW_DECODE, &message,
2810 failureId)) {
2811 featureVP9.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
2814 gfxVars::SetUseVP9HwDecode(featureVP9.IsEnabled());
2817 void gfxPlatform::InitWebGLConfig() {
2818 // Depends on InitWebRenderConfig() for UseWebRender().
2820 if (!XRE_IsParentProcess()) return;
2822 const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
2824 const auto IsFeatureOk = [&](const int32_t feature) {
2825 nsCString discardFailureId;
2826 int32_t status;
2827 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(
2828 gfxInfo->GetFeatureStatus(feature, discardFailureId, &status)));
2829 return (status == nsIGfxInfo::FEATURE_STATUS_OK);
2832 gfxVars::SetAllowWebgl2(IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL2));
2833 gfxVars::SetWebglAllowWindowsNativeGl(
2834 IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_OPENGL));
2835 gfxVars::SetAllowWebglAccelAngle(
2836 IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_ANGLE));
2838 if (kIsMacOS) {
2839 // Avoid crash for Intel HD Graphics 3000 on OSX. (Bug 1413269)
2840 nsString vendorID, deviceID;
2841 gfxInfo->GetAdapterVendorID(vendorID);
2842 gfxInfo->GetAdapterDeviceID(deviceID);
2843 if (vendorID.EqualsLiteral("0x8086") &&
2844 (deviceID.EqualsLiteral("0x0116") ||
2845 deviceID.EqualsLiteral("0x0126"))) {
2846 gfxVars::SetWebglAllowCoreProfile(false);
2850 bool allowWebGLOop =
2851 IsFeatureOk(nsIGfxInfo::FEATURE_ALLOW_WEBGL_OUT_OF_PROCESS);
2852 gfxVars::SetAllowWebglOop(allowWebGLOop);
2854 bool threadsafeGL = IsFeatureOk(nsIGfxInfo::FEATURE_THREADSAFE_GL);
2855 threadsafeGL |= StaticPrefs::webgl_threadsafe_gl_force_enabled_AtStartup();
2856 threadsafeGL &= !StaticPrefs::webgl_threadsafe_gl_force_disabled_AtStartup();
2857 gfxVars::SetSupportsThreadsafeGL(threadsafeGL);
2859 if (kIsAndroid) {
2860 // Don't enable robust buffer access on Adreno 630 devices.
2861 // It causes the linking of some shaders to fail. See bug 1485441.
2862 nsAutoString renderer;
2863 gfxInfo->GetAdapterDeviceID(renderer);
2864 if (renderer.Find("Adreno (TM) 630") != -1) {
2865 gfxVars::SetAllowEglRbab(false);
2869 if (kIsWayland || kIsX11) {
2870 nsCString discardFailureId;
2871 int32_t status;
2872 FeatureState& feature =
2873 gfxConfig::GetFeature(Feature::DMABUF_SURFACE_EXPORT);
2874 if (NS_FAILED(
2875 gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DMABUF_SURFACE_EXPORT,
2876 discardFailureId, &status)) ||
2877 status != nsIGfxInfo::FEATURE_STATUS_OK) {
2878 feature.DisableByDefault(FeatureStatus::Blocked, "Blocklisted by gfxInfo",
2879 discardFailureId);
2880 gfxVars::SetUseDMABufSurfaceExport(false);
2881 } else {
2882 feature.EnableByDefault();
2887 void gfxPlatform::InitWebGPUConfig() {
2888 if (!XRE_IsParentProcess()) {
2889 return;
2892 FeatureState& feature = gfxConfig::GetFeature(Feature::WEBGPU);
2893 feature.SetDefaultFromPref("dom.webgpu.enabled", true, false);
2895 nsCString message;
2896 nsCString failureId;
2897 if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_WEBGPU, &message, failureId)) {
2898 feature.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
2901 #ifdef RELEASE_OR_BETA
2902 feature.ForceDisable(FeatureStatus::Blocked,
2903 "WebGPU cannot be enabled in release or beta",
2904 "WEBGPU_DISABLE_RELEASE_OR_BETA"_ns);
2905 #else
2906 if (StaticPrefs::gfx_webgpu_force_enabled_AtStartup()) {
2907 feature.UserForceEnable("Force-enabled by pref");
2909 #endif
2911 gfxVars::SetAllowWebGPU(feature.IsEnabled());
2914 #ifdef XP_WIN
2915 static void WindowOcclusionPrefChangeCallback(const char* aPref, void*) {
2916 const char* env = PR_GetEnv("MOZ_WINDOW_OCCLUSION");
2917 if (env) {
2918 // env has a higher priority than pref.
2919 return;
2922 FeatureState& feature = gfxConfig::GetFeature(Feature::WINDOW_OCCLUSION);
2923 bool enabled =
2924 StaticPrefs::widget_windows_window_occlusion_tracking_enabled();
2926 printf_stderr("Dynamically enable window occlusion %d\n", enabled);
2928 // Update feature before calling WinUtils::EnableWindowOcclusion()
2929 if (enabled) {
2930 feature.UserEnable("User enabled by pref");
2931 } else {
2932 feature.UserDisable("User disabled via pref",
2933 "FEATURE_FAILURE_PREF_DISABLED"_ns);
2935 widget::WinUtils::EnableWindowOcclusion(enabled);
2937 #endif
2939 void gfxPlatform::InitWindowOcclusionConfig() {
2940 if (!XRE_IsParentProcess()) {
2941 return;
2943 #ifdef XP_WIN
2944 FeatureState& feature = gfxConfig::GetFeature(Feature::WINDOW_OCCLUSION);
2945 feature.SetDefaultFromPref(
2946 StaticPrefs::
2947 GetPrefName_widget_windows_window_occlusion_tracking_enabled(),
2948 true,
2949 StaticPrefs::
2950 GetPrefDefault_widget_windows_window_occlusion_tracking_enabled());
2952 const char* env = PR_GetEnv("MOZ_WINDOW_OCCLUSION");
2953 if (env) {
2954 if (*env == '1') {
2955 feature.UserForceEnable("Force enabled by envvar");
2956 } else {
2957 feature.UserDisable("Force disabled by envvar",
2958 "FEATURE_FAILURE_OCCL_ENV"_ns);
2962 Preferences::RegisterCallback(
2963 WindowOcclusionPrefChangeCallback,
2964 nsDependentCString(
2965 StaticPrefs::
2966 GetPrefName_widget_windows_window_occlusion_tracking_enabled()));
2967 #endif
2970 bool gfxPlatform::CanUseHardwareVideoDecoding() {
2971 // this function is called from the compositor thread, so it is not
2972 // safe to init the prefs etc. from here.
2973 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2974 return sLayersSupportsHardwareVideoDecoding &&
2975 !sLayersHardwareVideoDecodingFailed;
2978 bool gfxPlatform::AccelerateLayersByDefault() {
2979 #if defined(MOZ_GL_PROVIDER) || defined(MOZ_WIDGET_UIKIT)
2980 return true;
2981 #else
2982 return false;
2983 #endif
2986 /* static */
2987 bool gfxPlatform::UsesOffMainThreadCompositing() {
2988 if (XRE_GetProcessType() == GeckoProcessType_GPU) {
2989 return true;
2992 static bool firstTime = true;
2993 static bool result = false;
2995 if (firstTime) {
2996 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2997 result = gfxVars::BrowserTabsRemoteAutostart() ||
2998 !StaticPrefs::
2999 layers_offmainthreadcomposition_force_disabled_AtStartup();
3000 #if defined(MOZ_WIDGET_GTK)
3001 // Linux users who chose OpenGL are being included in OMTC
3002 result |= StaticPrefs::
3003 layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly();
3005 #endif
3006 firstTime = false;
3009 return result;
3012 RefPtr<mozilla::VsyncDispatcher> gfxPlatform::GetGlobalVsyncDispatcher() {
3013 MOZ_ASSERT(mVsyncDispatcher,
3014 "mVsyncDispatcher should have been initialized by ReInitFrameRate "
3015 "during gfxPlatform init");
3016 MOZ_ASSERT(XRE_IsParentProcess());
3017 return mVsyncDispatcher;
3020 already_AddRefed<mozilla::gfx::VsyncSource>
3021 gfxPlatform::GetGlobalHardwareVsyncSource() {
3022 if (!mGlobalHardwareVsyncSource) {
3023 mGlobalHardwareVsyncSource = CreateGlobalHardwareVsyncSource();
3025 return do_AddRef(mGlobalHardwareVsyncSource);
3028 /***
3029 * The preference "layout.frame_rate" has 3 meanings depending on the value:
3031 * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw
3032 * vsync fails.
3033 * 0 = ASAP mode - used during talos testing.
3034 * X = Software vsync at a rate of X times per second.
3036 already_AddRefed<mozilla::gfx::VsyncSource>
3037 gfxPlatform::GetSoftwareVsyncSource() {
3038 if (!mSoftwareVsyncSource) {
3039 double rateInMS = 1000.0 / (double)gfxPlatform::GetSoftwareVsyncRate();
3040 mSoftwareVsyncSource = new mozilla::gfx::SoftwareVsyncSource(
3041 TimeDuration::FromMilliseconds(rateInMS));
3043 return do_AddRef(mSoftwareVsyncSource);
3046 /* static */
3047 bool gfxPlatform::IsInLayoutAsapMode() {
3048 // There are 2 modes of ASAP mode.
3049 // 1 is that the refresh driver and compositor are in lock step
3050 // the second is that the compositor goes ASAP and the refresh driver
3051 // goes at whatever the configurated rate is. This only checks the version
3052 // talos uses, which is the refresh driver and compositor are in lockstep.
3053 // Ignore privacy_resistFingerprinting to preserve ASAP mode there.
3054 return StaticPrefs::layout_frame_rate() == 0;
3057 static int LayoutFrameRateFromPrefs() {
3058 auto val = StaticPrefs::layout_frame_rate();
3059 if (StaticPrefs::privacy_resistFingerprinting()) {
3060 val = 60;
3062 return val;
3065 /* static */
3066 bool gfxPlatform::ForceSoftwareVsync() {
3067 return LayoutFrameRateFromPrefs() > 0;
3070 /* static */
3071 int gfxPlatform::GetSoftwareVsyncRate() {
3072 int preferenceRate = LayoutFrameRateFromPrefs();
3073 if (preferenceRate <= 0) {
3074 return gfxPlatform::GetDefaultFrameRate();
3076 return preferenceRate;
3079 /* static */
3080 int gfxPlatform::GetDefaultFrameRate() { return 60; }
3082 /* static */
3083 void gfxPlatform::ReInitFrameRate(const char* aPrefIgnored,
3084 void* aDataIgnored) {
3085 MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
3087 if (gPlatform->mSoftwareVsyncSource) {
3088 // Update the rate of the existing software vsync source.
3089 double rateInMS = 1000.0 / (double)gfxPlatform::GetSoftwareVsyncRate();
3090 gPlatform->mSoftwareVsyncSource->SetVsyncRate(
3091 TimeDuration::FromMilliseconds(rateInMS));
3094 // Swap out the dispatcher's underlying source.
3095 RefPtr<VsyncSource> vsyncSource =
3096 gfxPlatform::ForceSoftwareVsync()
3097 ? gPlatform->GetSoftwareVsyncSource()
3098 : gPlatform->GetGlobalHardwareVsyncSource();
3099 gPlatform->mVsyncDispatcher->SetVsyncSource(vsyncSource);
3102 const char* gfxPlatform::GetAzureCanvasBackend() const {
3103 BackendType backend{};
3105 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
3106 // Assume content process' backend prefs.
3107 BackendPrefsData data = GetBackendPrefs();
3108 backend = GetCanvasBackendPref(data.mCanvasBitmask);
3109 if (backend == BackendType::NONE) {
3110 backend = data.mCanvasDefault;
3112 } else {
3113 backend = mPreferredCanvasBackend;
3116 return GetBackendName(backend);
3119 const char* gfxPlatform::GetAzureContentBackend() const {
3120 BackendType backend{};
3122 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
3123 // Assume content process' backend prefs.
3124 BackendPrefsData data = GetBackendPrefs();
3125 backend = GetContentBackendPref(data.mContentBitmask);
3126 if (backend == BackendType::NONE) {
3127 backend = data.mContentDefault;
3129 } else {
3130 backend = mContentBackend;
3133 return GetBackendName(backend);
3136 void gfxPlatform::GetAzureBackendInfo(mozilla::widget::InfoObject& aObj) {
3137 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
3138 aObj.DefineProperty("AzureCanvasBackend (UI Process)",
3139 GetBackendName(mPreferredCanvasBackend));
3140 aObj.DefineProperty("AzureFallbackCanvasBackend (UI Process)",
3141 GetBackendName(mFallbackCanvasBackend));
3142 aObj.DefineProperty("AzureContentBackend (UI Process)",
3143 GetBackendName(mContentBackend));
3144 } else {
3145 aObj.DefineProperty("AzureFallbackCanvasBackend",
3146 GetBackendName(mFallbackCanvasBackend));
3149 aObj.DefineProperty("AzureCanvasBackend", GetAzureCanvasBackend());
3150 aObj.DefineProperty("AzureContentBackend", GetAzureContentBackend());
3153 void gfxPlatform::GetApzSupportInfo(mozilla::widget::InfoObject& aObj) {
3154 if (!gfxPlatform::AsyncPanZoomEnabled()) {
3155 return;
3158 if (SupportsApzWheelInput()) {
3159 aObj.DefineProperty("ApzWheelInput", 1);
3162 if (SupportsApzTouchInput()) {
3163 aObj.DefineProperty("ApzTouchInput", 1);
3166 if (SupportsApzDragInput()) {
3167 aObj.DefineProperty("ApzDragInput", 1);
3170 if (SupportsApzKeyboardInput() &&
3171 !StaticPrefs::accessibility_browsewithcaret()) {
3172 aObj.DefineProperty("ApzKeyboardInput", 1);
3175 if (SupportsApzAutoscrolling()) {
3176 aObj.DefineProperty("ApzAutoscrollInput", 1);
3179 if (SupportsApzZooming()) {
3180 aObj.DefineProperty("ApzZoomingInput", 1);
3184 void gfxPlatform::GetFrameStats(mozilla::widget::InfoObject& aObj) {
3185 uint32_t i = 0;
3186 for (FrameStats& f : mFrameStats) {
3187 nsPrintfCString name("Slow Frame #%02u", ++i);
3189 nsPrintfCString value(
3190 "Frame %" PRIu64
3191 "(%s) CONTENT_FRAME_TIME %d - Transaction start %f, main-thread time "
3192 "%f, full paint time %f, Skipped composites %u, Composite start %f, "
3193 "Resource upload time %f, GPU cache upload time %f, Render time %f, "
3194 "Composite time %f",
3195 f.id().mId, f.url().get(), f.contentFrameTime(),
3196 (f.transactionStart() - f.refreshStart()).ToMilliseconds(),
3197 (f.fwdTime() - f.transactionStart()).ToMilliseconds(),
3198 f.sceneBuiltTime()
3199 ? (f.sceneBuiltTime() - f.transactionStart()).ToMilliseconds()
3200 : 0.0,
3201 f.skippedComposites(),
3202 (f.compositeStart() - f.refreshStart()).ToMilliseconds(),
3203 f.resourceUploadTime(), f.gpuCacheUploadTime(),
3204 (f.compositeEnd() - f.renderStart()).ToMilliseconds(),
3205 (f.compositeEnd() - f.compositeStart()).ToMilliseconds());
3206 aObj.DefineProperty(name.get(), value.get());
3210 void gfxPlatform::GetCMSSupportInfo(mozilla::widget::InfoObject& aObj) {
3211 nsTArray<uint8_t> outputProfileData =
3212 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfileData();
3213 if (outputProfileData.IsEmpty()) {
3214 nsPrintfCString msg("Empty profile data");
3215 aObj.DefineProperty("CMSOutputProfile", msg.get());
3216 return;
3219 // Some profiles can be quite large. We don't want to include giant profiles
3220 // by default in about:support. For now, we only accept less than 8kiB.
3221 const size_t kMaxProfileSize = 8192;
3222 if (outputProfileData.Length() >= kMaxProfileSize) {
3223 nsPrintfCString msg("%zu bytes, too large", outputProfileData.Length());
3224 aObj.DefineProperty("CMSOutputProfile", msg.get());
3225 return;
3228 nsString encodedProfile;
3229 nsresult rv =
3230 Base64Encode(reinterpret_cast<const char*>(outputProfileData.Elements()),
3231 outputProfileData.Length(), encodedProfile);
3232 if (!NS_SUCCEEDED(rv)) {
3233 nsPrintfCString msg("base64 encode failed 0x%08x",
3234 static_cast<uint32_t>(rv));
3235 aObj.DefineProperty("CMSOutputProfile", msg.get());
3236 return;
3239 aObj.DefineProperty("CMSOutputProfile", encodedProfile);
3242 void gfxPlatform::GetDisplayInfo(mozilla::widget::InfoObject& aObj) {
3243 auto& screens = widget::ScreenManager::GetSingleton().CurrentScreenList();
3244 aObj.DefineProperty("DisplayCount", screens.Length());
3246 size_t i = 0;
3247 for (auto& screen : screens) {
3248 const LayoutDeviceIntRect rect = screen->GetRect();
3249 nsPrintfCString value("%dx%d@%dHz scales:%f|%f", rect.width, rect.height,
3250 screen->GetRefreshRate(),
3251 screen->GetContentsScaleFactor(),
3252 screen->GetDefaultCSSScaleFactor());
3254 aObj.DefineProperty(nsPrintfCString("Display%zu", i++).get(),
3255 NS_ConvertUTF8toUTF16(value));
3258 // Platform display info is only currently used for about:support and getting
3259 // it might fail in a child process anyway.
3260 if (XRE_IsParentProcess()) {
3261 GetPlatformDisplayInfo(aObj);
3265 void gfxPlatform::GetOverlayInfo(mozilla::widget::InfoObject& aObj) {
3266 if (mOverlayInfo.isNothing()) {
3267 return;
3270 auto toString = [](mozilla::layers::OverlaySupportType aType) -> const char* {
3271 switch (aType) {
3272 case mozilla::layers::OverlaySupportType::None:
3273 return "None";
3274 case mozilla::layers::OverlaySupportType::Software:
3275 return "Software";
3276 case mozilla::layers::OverlaySupportType::Direct:
3277 return "Direct";
3278 case mozilla::layers::OverlaySupportType::Scaling:
3279 return "Scaling";
3280 default:
3281 MOZ_ASSERT_UNREACHABLE("Unexpected to be called");
3283 MOZ_CRASH("Incomplete switch");
3286 nsPrintfCString value("NV12=%s YUV2=%s BGRA8=%s RGB10A2=%s",
3287 toString(mOverlayInfo.ref().mNv12Overlay),
3288 toString(mOverlayInfo.ref().mYuy2Overlay),
3289 toString(mOverlayInfo.ref().mBgra8Overlay),
3290 toString(mOverlayInfo.ref().mRgb10a2Overlay));
3292 aObj.DefineProperty("OverlaySupport", NS_ConvertUTF8toUTF16(value));
3295 class FrameStatsComparator {
3296 public:
3297 bool Equals(const FrameStats& aA, const FrameStats& aB) const {
3298 return aA.contentFrameTime() == aB.contentFrameTime();
3300 // Reverse the condition here since we want the array sorted largest to
3301 // smallest.
3302 bool LessThan(const FrameStats& aA, const FrameStats& aB) const {
3303 return aA.contentFrameTime() > aB.contentFrameTime();
3307 void gfxPlatform::NotifyFrameStats(nsTArray<FrameStats>&& aFrameStats) {
3308 if (!StaticPrefs::gfx_logging_slow_frames_enabled_AtStartup()) {
3309 return;
3312 FrameStatsComparator comp;
3313 for (FrameStats& f : aFrameStats) {
3314 mFrameStats.InsertElementSorted(f, comp);
3316 if (mFrameStats.Length() > 10) {
3317 mFrameStats.SetLength(10);
3321 /*static*/
3322 uint32_t gfxPlatform::TargetFrameRate() {
3323 if (gPlatform && gPlatform->mVsyncDispatcher) {
3324 return round(1000.0 /
3325 gPlatform->mVsyncDispatcher->GetVsyncRate().ToMilliseconds());
3327 return 0;
3330 /* static */
3331 bool gfxPlatform::UseDesktopZoomingScrollbars() {
3332 return StaticPrefs::apz_allow_zooming() &&
3333 !StaticPrefs::apz_force_disable_desktop_zooming_scrollbars();
3336 /*static*/
3337 bool gfxPlatform::AsyncPanZoomEnabled() {
3338 #if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
3339 // For XUL applications (everything but Firefox on Android)
3340 // we only want to use APZ when E10S is enabled. If
3341 // we ever get input events off the main thread we can consider relaxing
3342 // this requirement.
3343 if (!BrowserTabsRemoteAutostart()) {
3344 return false;
3346 #endif
3347 #ifdef MOZ_WIDGET_ANDROID
3348 return true;
3349 #else
3350 // If Fission is enabled, OOP iframes require APZ for hittest. So, we
3351 // need to forcibly enable APZ in that case for avoiding users confused.
3352 if (FissionAutostart()) {
3353 return true;
3355 return StaticPrefs::
3356 layers_async_pan_zoom_enabled_AtStartup_DoNotUseDirectly();
3357 #endif
3360 /*static*/
3361 bool gfxPlatform::PerfWarnings() {
3362 return StaticPrefs::gfx_perf_warnings_enabled();
3365 void gfxPlatform::NotifyCompositorCreated(LayersBackend aBackend) {
3366 if (mCompositorBackend == aBackend) {
3367 return;
3370 if (mCompositorBackend != LayersBackend::LAYERS_NONE) {
3371 gfxCriticalNote << "Compositors might be mixed (" << int(mCompositorBackend)
3372 << "," << int(aBackend) << ")";
3375 // Set the backend before we notify so it's available immediately.
3376 mCompositorBackend = aBackend;
3378 if (XRE_IsParentProcess()) {
3379 Telemetry::ScalarSet(
3380 Telemetry::ScalarID::GFX_COMPOSITOR,
3381 NS_ConvertUTF8toUTF16(GetLayersBackendName(mCompositorBackend)));
3383 nsCString geckoVersion;
3384 nsCOMPtr<nsIXULAppInfo> app = do_GetService("@mozilla.org/xre/app-info;1");
3385 if (app) {
3386 app->GetVersion(geckoVersion);
3388 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_LAST_COMPOSITOR_GECKO_VERSION,
3389 NS_ConvertASCIItoUTF16(geckoVersion));
3391 Telemetry::ScalarSet(
3392 Telemetry::ScalarID::GFX_FEATURE_WEBRENDER,
3393 NS_ConvertUTF8toUTF16(gfxConfig::GetFeature(gfx::Feature::WEBRENDER)
3394 .GetStatusAndFailureIdString()));
3397 // Notify that we created a compositor, so telemetry can update.
3398 NS_DispatchToMainThread(
3399 NS_NewRunnableFunction("gfxPlatform::NotifyCompositorCreated", [] {
3400 if (nsCOMPtr<nsIObserverService> obsvc =
3401 services::GetObserverService()) {
3402 obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
3404 }));
3407 /* static */
3408 bool gfxPlatform::FallbackFromAcceleration(FeatureStatus aStatus,
3409 const char* aMessage,
3410 const nsACString& aFailureId,
3411 bool aCrashAfterFinalFallback) {
3412 // We always want to ensure (Hardware) WebRender is disabled.
3413 if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
3414 gfxConfig::GetFeature(Feature::WEBRENDER)
3415 .ForceDisable(aStatus, aMessage, aFailureId);
3418 // Determine whether or not we are allowed to use Software WebRender in
3419 // fallback without the GPU process. Either the pref is false, or the feature
3420 // is enabled and we are currently still using it.
3421 bool swglFallbackAllowed =
3422 !StaticPrefs::
3423 gfx_webrender_fallback_software_requires_gpu_process_AtStartup() ||
3424 gfxConfig::IsEnabled(Feature::GPU_PROCESS);
3426 #ifdef XP_WIN
3427 // Before we disable D3D11 and HW_COMPOSITING, we should check if we can
3428 // fallback from WebRender to Software WebRender + D3D11 compositing.
3429 if (StaticPrefs::gfx_webrender_fallback_software_d3d11_AtStartup() &&
3430 swglFallbackAllowed && gfxVars::AllowSoftwareWebRenderD3D11() &&
3431 gfxConfig::IsEnabled(Feature::WEBRENDER_SOFTWARE) &&
3432 gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING) &&
3433 gfxVars::UseWebRender() && !gfxVars::UseSoftwareWebRender()) {
3434 // Fallback to Software WebRender + D3D11 compositing.
3435 gfxCriticalNote << "Fallback WR to SW-WR + D3D11";
3436 gfxVars::SetUseSoftwareWebRender(true);
3437 return true;
3440 if (StaticPrefs::gfx_webrender_fallback_software_d3d11_AtStartup() &&
3441 swglFallbackAllowed && gfxVars::AllowSoftwareWebRenderD3D11() &&
3442 gfxVars::UseSoftwareWebRender()) {
3443 // Fallback from Software WebRender + D3D11 to Software WebRender.
3444 gfxCriticalNote << "Fallback SW-WR + D3D11 to SW-WR";
3445 gfxVars::SetAllowSoftwareWebRenderD3D11(false);
3446 return true;
3449 // We aren't using Software WebRender + D3D11 compositing, so turn off the
3450 // D3D11 and D2D.
3451 if (gfxConfig::IsEnabled(Feature::DIRECT2D)) {
3452 gfxConfig::GetFeature(Feature::DIRECT2D)
3453 .ForceDisable(aStatus, aMessage, aFailureId);
3455 if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
3456 gfxConfig::GetFeature(Feature::D3D11_COMPOSITING)
3457 .ForceDisable(aStatus, aMessage, aFailureId);
3459 if (StaticPrefs::gfx_webrender_fallback_software_AtStartup() &&
3460 swglFallbackAllowed &&
3461 gfxConfig::IsEnabled(Feature::WEBRENDER_SOFTWARE) &&
3462 !gfxVars::UseWebRender()) {
3463 // Fallback from D3D11 to Software WebRender.
3464 gfxCriticalNote << "Fallback D3D11 to SW-WR";
3465 gfxVars::SetUseWebRender(true);
3466 gfxVars::SetUseSoftwareWebRender(true);
3467 return true;
3470 #endif
3472 #ifndef MOZ_WIDGET_ANDROID
3473 // Non-Android wants to fallback to Software WebRender or Basic. Android wants
3474 // to fallback to OpenGL.
3475 if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
3476 gfxConfig::GetFeature(Feature::HW_COMPOSITING)
3477 .ForceDisable(aStatus, aMessage, aFailureId);
3479 #endif
3481 if (!gfxVars::UseWebRender()) {
3482 // We were not using WebRender in the first place, and we have disabled
3483 // all forms of accelerated compositing.
3484 return false;
3487 if (StaticPrefs::gfx_webrender_fallback_software_AtStartup() &&
3488 swglFallbackAllowed &&
3489 gfxConfig::IsEnabled(Feature::WEBRENDER_SOFTWARE) &&
3490 !gfxVars::UseSoftwareWebRender()) {
3491 // Fallback from WebRender to Software WebRender.
3492 gfxCriticalNote << "Fallback WR to SW-WR";
3493 gfxVars::SetUseSoftwareWebRender(true);
3494 return true;
3497 MOZ_ASSERT(gfxVars::UseWebRender());
3499 if (!gfxVars::UseSoftwareWebRender()) {
3500 // Software WebRender may be disabled due to a startup issue with the
3501 // blocklist, despite it being our only fallback option based on the prefs.
3502 // If WebRender is unable to be initialized, this means that user would
3503 // otherwise get stuck with WebRender. As such, force a switch to Software
3504 // WebRender in this case.
3505 gfxCriticalNoteOnce << "Fallback WR to SW-WR, forced";
3506 gfxVars::SetUseSoftwareWebRender(true);
3507 return true;
3510 if (aCrashAfterFinalFallback) {
3511 MOZ_CRASH("Fallback configurations exhausted");
3514 // Continue using Software WebRender (disabled fallback to Basic).
3515 gfxCriticalNoteOnce << "Fallback remains SW-WR";
3516 return false;
3519 /* static */
3520 void gfxPlatform::DisableGPUProcess() {
3521 gfxVars::SetRemoteCanvasEnabled(false);
3523 RemoteTextureMap::Init();
3524 if (gfxVars::UseWebRender()) {
3525 // We need to initialize the parent process to prepare for WebRender if we
3526 // did not end up disabling it, despite losing the GPU process.
3527 wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());
3528 image::ImageMemoryReporter::InitForWebRender();
3532 void gfxPlatform::FetchAndImportContentDeviceData() {
3533 MOZ_ASSERT(XRE_IsContentProcess());
3535 if (gContentDeviceInitData) {
3536 ImportContentDeviceData(*gContentDeviceInitData);
3537 return;
3540 mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
3542 mozilla::gfx::ContentDeviceData data;
3543 cc->SendGetGraphicsDeviceInitData(&data);
3545 ImportContentDeviceData(data);
3548 void gfxPlatform::ImportContentDeviceData(
3549 const mozilla::gfx::ContentDeviceData& aData) {
3550 MOZ_ASSERT(XRE_IsContentProcess());
3552 const DevicePrefs& prefs = aData.prefs();
3553 gfxConfig::Inherit(Feature::HW_COMPOSITING, prefs.hwCompositing());
3554 gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, prefs.oglCompositing());
3557 void gfxPlatform::BuildContentDeviceData(
3558 mozilla::gfx::ContentDeviceData* aOut) {
3559 MOZ_ASSERT(XRE_IsParentProcess());
3561 // Make sure our settings are synchronized from the GPU process.
3562 GPUProcessManager::Get()->EnsureGPUReady();
3564 aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
3565 aOut->prefs().oglCompositing() =
3566 gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
3569 void gfxPlatform::ImportGPUDeviceData(
3570 const mozilla::gfx::GPUDeviceData& aData) {
3571 MOZ_ASSERT(XRE_IsParentProcess());
3573 gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
3576 bool gfxPlatform::SupportsApzTouchInput() const {
3577 return dom::TouchEvent::PrefEnabled(nullptr);
3580 bool gfxPlatform::SupportsApzDragInput() const {
3581 return StaticPrefs::apz_drag_enabled();
3584 bool gfxPlatform::SupportsApzKeyboardInput() const {
3585 return StaticPrefs::apz_keyboard_enabled_AtStartup();
3588 bool gfxPlatform::SupportsApzAutoscrolling() const {
3589 return StaticPrefs::apz_autoscroll_enabled();
3592 bool gfxPlatform::SupportsApzZooming() const {
3593 return StaticPrefs::apz_allow_zooming();
3596 void gfxPlatform::InitOpenGLConfig() {
3597 #ifdef XP_WIN
3598 // Don't enable by default on Windows, since it could show up in about:support
3599 // even though it'll never get used. Only attempt if user enables the pref
3600 if (!Preferences::GetBool("layers.prefer-opengl")) {
3601 return;
3603 #endif
3605 FeatureState& openGLFeature =
3606 gfxConfig::GetFeature(Feature::OPENGL_COMPOSITING);
3608 // Check to see hw comp supported
3609 if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
3610 openGLFeature.DisableByDefault(FeatureStatus::Unavailable,
3611 "Hardware compositing is disabled",
3612 "FEATURE_FAILURE_OPENGL_NEED_HWCOMP"_ns);
3613 return;
3616 #ifdef XP_WIN
3617 openGLFeature.SetDefaultFromPref(
3618 StaticPrefs::GetPrefName_layers_prefer_opengl(), true,
3619 StaticPrefs::GetPrefDefault_layers_prefer_opengl());
3620 #else
3621 openGLFeature.EnableByDefault();
3622 #endif
3624 // When layers acceleration is force-enabled, enable it even for blocklisted
3625 // devices.
3626 if (StaticPrefs::
3627 layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly()) {
3628 openGLFeature.UserForceEnable("Force-enabled by pref");
3629 return;
3632 nsCString message;
3633 nsCString failureId;
3634 if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &message,
3635 failureId)) {
3636 openGLFeature.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
3640 bool gfxPlatform::IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage,
3641 nsCString& aFailureId) {
3642 nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
3643 if (!gfxInfo) {
3644 return true;
3647 int32_t status;
3648 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) &&
3649 status != nsIGfxInfo::FEATURE_STATUS_OK) {
3650 aOutMessage->AssignLiteral("#BLOCKLIST_");
3651 aOutMessage->AppendASCII(aFailureId.get());
3652 return false;
3655 return true;