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