Bug 1444940 [wpt PR 9917] - Writable streams: test changes to abort() under error...
[gecko.git] / gfx / thebes / gfxPlatform.cpp
blob341c097a2c1d4f7d4dfb68c18f4705a3c49221b6
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/layers/CompositorManagerChild.h"
7 #include "mozilla/layers/CompositorThread.h"
8 #include "mozilla/layers/ImageBridgeChild.h"
9 #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
10 #include "mozilla/layers/SharedSurfacesParent.h"
11 #include "mozilla/webrender/RenderThread.h"
12 #include "mozilla/webrender/WebRenderAPI.h"
13 #include "mozilla/webrender/webrender_ffi.h"
14 #include "mozilla/layers/PaintThread.h"
15 #include "mozilla/gfx/gfxVars.h"
16 #include "mozilla/gfx/GPUProcessManager.h"
17 #include "mozilla/gfx/GraphicsMessages.h"
18 #include "mozilla/ClearOnShutdown.h"
19 #include "mozilla/Telemetry.h"
20 #include "mozilla/TimeStamp.h"
21 #include "mozilla/Unused.h"
23 #include "mozilla/Logging.h"
24 #include "mozilla/Services.h"
26 #include "gfxCrashReporterUtils.h"
27 #include "gfxPlatform.h"
28 #include "gfxPrefs.h"
29 #include "gfxEnv.h"
30 #include "gfxTextRun.h"
31 #include "gfxUserFontSet.h"
32 #include "gfxConfig.h"
33 #include "MediaPrefs.h"
34 #include "VRThread.h"
36 #ifdef XP_WIN
37 #include <process.h>
38 #define getpid _getpid
39 #else
40 #include <unistd.h>
41 #endif
43 #include "nsXULAppAPI.h"
44 #include "nsDirectoryServiceUtils.h"
45 #include "nsDirectoryServiceDefs.h"
47 #if defined(XP_WIN)
48 #include "gfxWindowsPlatform.h"
49 #elif defined(XP_MACOSX)
50 #include "gfxPlatformMac.h"
51 #include "gfxQuartzSurface.h"
52 #elif defined(MOZ_WIDGET_GTK)
53 #include "gfxPlatformGtk.h"
54 #elif defined(ANDROID)
55 #include "gfxAndroidPlatform.h"
56 #endif
58 #ifdef XP_WIN
59 #include "mozilla/WindowsVersion.h"
60 #include "mozilla/gfx/DeviceManagerDx.h"
61 #endif
63 #include "nsGkAtoms.h"
64 #include "gfxPlatformFontList.h"
65 #include "gfxContext.h"
66 #include "gfxImageSurface.h"
67 #include "nsUnicodeProperties.h"
68 #include "harfbuzz/hb.h"
69 #include "gfxGraphiteShaper.h"
70 #include "gfx2DGlue.h"
71 #include "gfxGradientCache.h"
72 #include "gfxUtils.h" // for NextPowerOfTwo
74 #include "nsExceptionHandler.h"
75 #include "nsUnicodeRange.h"
76 #include "nsServiceManagerUtils.h"
77 #include "nsTArray.h"
78 #include "nsIObserverService.h"
79 #include "nsIScreenManager.h"
80 #include "FrameMetrics.h"
81 #include "MainThreadUtils.h"
83 #include "nsWeakReference.h"
85 #include "cairo.h"
86 #include "qcms.h"
88 #include "imgITools.h"
90 #include "plstr.h"
91 #include "nsCRT.h"
92 #include "GLContext.h"
93 #include "GLContextProvider.h"
94 #include "mozilla/gfx/Logging.h"
96 #ifdef USE_SKIA
97 # ifdef __GNUC__
98 # pragma GCC diagnostic push
99 # pragma GCC diagnostic ignored "-Wshadow"
100 # endif
101 # include "skia/include/core/SkGraphics.h"
102 # ifdef USE_SKIA_GPU
103 # include "skia/include/gpu/GrContext.h"
104 # include "skia/include/gpu/gl/GrGLInterface.h"
105 # include "SkiaGLGlue.h"
106 # endif
107 # ifdef MOZ_ENABLE_FREETYPE
108 # include "skia/include/ports/SkTypeface_cairo.h"
109 # endif
110 # ifdef __GNUC__
111 # pragma GCC diagnostic pop // -Wshadow
112 # endif
113 static const uint32_t kDefaultGlyphCacheSize = -1;
115 #endif
117 #if !defined(USE_SKIA) || !defined(USE_SKIA_GPU)
118 class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
120 #endif
122 #include "mozilla/Preferences.h"
123 #include "mozilla/Assertions.h"
124 #include "mozilla/Atomics.h"
125 #include "mozilla/Attributes.h"
126 #include "mozilla/Mutex.h"
128 #include "nsAlgorithm.h"
129 #include "nsIGfxInfo.h"
130 #include "nsIXULRuntime.h"
131 #include "VsyncSource.h"
132 #include "SoftwareVsyncSource.h"
133 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
134 #include "mozilla/dom/ContentChild.h"
135 #include "mozilla/dom/TouchEvent.h"
136 #include "gfxVR.h"
137 #include "VRManagerChild.h"
138 #include "mozilla/gfx/GPUParent.h"
139 #include "mozilla/layers/MemoryReportingMLGPU.h"
140 #include "prsystem.h"
142 namespace mozilla {
143 namespace layers {
144 void ShutdownTileCache();
145 } // namespace layers
146 } // namespace mozilla
148 using namespace mozilla;
149 using namespace mozilla::layers;
150 using namespace mozilla::gl;
151 using namespace mozilla::gfx;
153 gfxPlatform *gPlatform = nullptr;
154 static bool gEverInitialized = false;
156 const ContentDeviceData* gContentDeviceInitData = nullptr;
158 static Mutex* gGfxPlatformPrefsLock = nullptr;
160 // These two may point to the same profile
161 static qcms_profile *gCMSOutputProfile = nullptr;
162 static qcms_profile *gCMSsRGBProfile = nullptr;
164 static qcms_transform *gCMSRGBTransform = nullptr;
165 static qcms_transform *gCMSInverseRGBTransform = nullptr;
166 static qcms_transform *gCMSRGBATransform = nullptr;
168 static bool gCMSInitialized = false;
169 static eCMSMode gCMSMode = eCMSMode_Off;
171 static void ShutdownCMS();
173 #include "mozilla/gfx/2D.h"
174 #include "mozilla/gfx/SourceSurfaceCairo.h"
175 using namespace mozilla::gfx;
177 /* Class to listen for pref changes so that chrome code can dynamically
178 force sRGB as an output profile. See Bug #452125. */
179 class SRGBOverrideObserver final : public nsIObserver,
180 public nsSupportsWeakReference
182 ~SRGBOverrideObserver() = default;
183 public:
184 NS_DECL_ISUPPORTS
185 NS_DECL_NSIOBSERVER
188 /// This override of the LogForwarder, initially used for the critical graphics
189 /// errors, is sending the log to the crash annotations as well, but only
190 /// if the capacity set with the method below is >= 2. We always retain the
191 /// very first critical message, and the latest capacity-1 messages are
192 /// rotated through. Note that we don't expect the total number of times
193 /// this gets called to be large - it is meant for critical errors only.
195 class CrashStatsLogForwarder: public mozilla::gfx::LogForwarder
197 public:
198 explicit CrashStatsLogForwarder(const char* aKey);
199 void Log(const std::string& aString) override;
200 void CrashAction(LogReason aReason) override;
201 bool UpdateStringsVector(const std::string& aString) override;
203 LoggingRecord LoggingRecordCopy() override;
205 void SetCircularBufferSize(uint32_t aCapacity);
207 private:
208 // Helper for the Log()
209 void UpdateCrashReport();
211 private:
212 LoggingRecord mBuffer;
213 nsCString mCrashCriticalKey;
214 uint32_t mMaxCapacity;
215 int32_t mIndex;
216 Mutex mMutex;
219 CrashStatsLogForwarder::CrashStatsLogForwarder(const char* aKey)
220 : mBuffer()
221 , mCrashCriticalKey(aKey)
222 , mMaxCapacity(0)
223 , mIndex(-1)
224 , mMutex("CrashStatsLogForwarder")
228 void CrashStatsLogForwarder::SetCircularBufferSize(uint32_t aCapacity)
230 MutexAutoLock lock(mMutex);
232 mMaxCapacity = aCapacity;
233 mBuffer.reserve(static_cast<size_t>(aCapacity));
236 LoggingRecord
237 CrashStatsLogForwarder::LoggingRecordCopy()
239 MutexAutoLock lock(mMutex);
240 return mBuffer;
243 bool
244 CrashStatsLogForwarder::UpdateStringsVector(const std::string& aString)
246 // We want at least the first one and the last one. Otherwise, no point.
247 if (mMaxCapacity < 2) {
248 return false;
251 mIndex += 1;
252 MOZ_ASSERT(mIndex >= 0);
254 // index will count 0, 1, 2, ..., max-1, 1, 2, ..., max-1, 1, 2, ...
255 int32_t index = mIndex ? (mIndex-1) % (mMaxCapacity-1) + 1 : 0;
256 MOZ_ASSERT(index >= 0 && index < (int32_t)mMaxCapacity);
257 MOZ_ASSERT(index <= mIndex && index <= (int32_t)mBuffer.size());
259 double tStamp = (TimeStamp::NowLoRes() - TimeStamp::ProcessCreation()).ToSecondsSigDigits();
261 // Checking for index >= mBuffer.size(), rather than index == mBuffer.size()
262 // just out of paranoia, but we know index <= mBuffer.size().
263 LoggingRecordEntry newEntry(mIndex,aString,tStamp);
264 if (index >= static_cast<int32_t>(mBuffer.size())) {
265 mBuffer.push_back(newEntry);
266 } else {
267 mBuffer[index] = newEntry;
269 return true;
272 void CrashStatsLogForwarder::UpdateCrashReport()
274 std::stringstream message;
275 std::string logAnnotation;
277 switch (XRE_GetProcessType()) {
278 case GeckoProcessType_Default:
279 logAnnotation = "|[";
280 break;
281 case GeckoProcessType_Content:
282 logAnnotation = "|[C";
283 break;
284 case GeckoProcessType_GPU:
285 logAnnotation = "|[G";
286 break;
287 default:
288 logAnnotation = "|[X";
289 break;
292 for (auto& it : mBuffer) {
293 message << logAnnotation << Get<0>(it) << "]" << Get<1>(it) << " (t=" << Get<2>(it) << ") ";
296 nsCString reportString(message.str().c_str());
297 nsresult annotated = CrashReporter::AnnotateCrashReport(mCrashCriticalKey, reportString);
299 if (annotated != NS_OK) {
300 printf("Crash Annotation %s: %s",
301 mCrashCriticalKey.get(), message.str().c_str());
305 class LogForwarderEvent : public Runnable
307 ~LogForwarderEvent() override = default;
309 public:
310 NS_INLINE_DECL_REFCOUNTING_INHERITED(LogForwarderEvent, Runnable)
312 explicit LogForwarderEvent(const nsCString& aMessage)
313 : mozilla::Runnable("LogForwarderEvent")
314 , mMessage(aMessage)
318 NS_IMETHOD Run() override {
319 MOZ_ASSERT(NS_IsMainThread() && (XRE_IsContentProcess() || XRE_IsGPUProcess()));
321 if (XRE_IsContentProcess()) {
322 dom::ContentChild* cc = dom::ContentChild::GetSingleton();
323 Unused << cc->SendGraphicsError(mMessage);
324 } else if (XRE_IsGPUProcess()) {
325 GPUParent* gp = GPUParent::GetSingleton();
326 Unused << gp->SendGraphicsError(mMessage);
329 return NS_OK;
332 protected:
333 nsCString mMessage;
336 void CrashStatsLogForwarder::Log(const std::string& aString)
338 MutexAutoLock lock(mMutex);
340 if (UpdateStringsVector(aString)) {
341 UpdateCrashReport();
344 // Add it to the parent strings
345 if (!XRE_IsParentProcess()) {
346 nsCString stringToSend(aString.c_str());
347 if (NS_IsMainThread()) {
348 if (XRE_IsContentProcess()) {
349 dom::ContentChild* cc = dom::ContentChild::GetSingleton();
350 Unused << cc->SendGraphicsError(stringToSend);
351 } else if (XRE_IsGPUProcess()) {
352 GPUParent* gp = GPUParent::GetSingleton();
353 Unused << gp->SendGraphicsError(stringToSend);
355 } else {
356 nsCOMPtr<nsIRunnable> r1 = new LogForwarderEvent(stringToSend);
357 NS_DispatchToMainThread(r1);
362 class CrashTelemetryEvent : public Runnable
364 ~CrashTelemetryEvent() override = default;
366 public:
367 NS_INLINE_DECL_REFCOUNTING_INHERITED(CrashTelemetryEvent, Runnable)
369 explicit CrashTelemetryEvent(uint32_t aReason)
370 : mozilla::Runnable("CrashTelemetryEvent")
371 , mReason(aReason)
375 NS_IMETHOD Run() override {
376 MOZ_ASSERT(NS_IsMainThread());
377 Telemetry::Accumulate(Telemetry::GFX_CRASH, mReason);
378 return NS_OK;
381 protected:
382 uint32_t mReason;
385 void
386 CrashStatsLogForwarder::CrashAction(LogReason aReason)
388 #ifndef RELEASE_OR_BETA
389 // Non-release builds crash by default, but will use telemetry
390 // if this environment variable is present.
391 static bool useTelemetry = gfxEnv::GfxDevCrashTelemetry();
392 #else
393 // Release builds use telemetry by default, but will crash instead
394 // if this environment variable is present.
395 static bool useTelemetry = !gfxEnv::GfxDevCrashMozCrash();
396 #endif
398 if (useTelemetry) {
399 // The callers need to assure that aReason is in the range
400 // that the telemetry call below supports.
401 if (NS_IsMainThread()) {
402 Telemetry::Accumulate(Telemetry::GFX_CRASH, (uint32_t)aReason);
403 } else {
404 nsCOMPtr<nsIRunnable> r1 = new CrashTelemetryEvent((uint32_t)aReason);
405 NS_DispatchToMainThread(r1);
407 } else {
408 // ignoring aReason, we can get the information we need from the stack
409 MOZ_CRASH("GFX_CRASH");
413 NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
415 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
417 #define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps"
419 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
421 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
422 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
424 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
426 #define BIDI_NUMERAL_PREF "bidi.numeral"
428 #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb"
430 NS_IMETHODIMP
431 SRGBOverrideObserver::Observe(nsISupports *aSubject,
432 const char *aTopic,
433 const char16_t* someData)
435 NS_ASSERTION(NS_strcmp(someData,
436 (u"" GFX_PREF_CMS_FORCE_SRGB)) == 0,
437 "Restarting CMS on wrong pref!");
438 ShutdownCMS();
439 // Update current cms profile.
440 gfxPlatform::CreateCMSOutputProfile();
441 return NS_OK;
444 static const char* kObservedPrefs[] = {
445 "gfx.downloadable_fonts.",
446 "gfx.font_rendering.",
447 BIDI_NUMERAL_PREF,
448 nullptr
451 class FontPrefsObserver final : public nsIObserver
453 ~FontPrefsObserver() = default;
454 public:
455 NS_DECL_ISUPPORTS
456 NS_DECL_NSIOBSERVER
459 NS_IMPL_ISUPPORTS(FontPrefsObserver, nsIObserver)
461 NS_IMETHODIMP
462 FontPrefsObserver::Observe(nsISupports *aSubject,
463 const char *aTopic,
464 const char16_t *someData)
466 if (!someData) {
467 NS_ERROR("font pref observer code broken");
468 return NS_ERROR_UNEXPECTED;
470 NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
471 gfxPlatform::GetPlatform()->FontsPrefsChanged(NS_ConvertUTF16toUTF8(someData).get());
473 return NS_OK;
476 class MemoryPressureObserver final : public nsIObserver
478 ~MemoryPressureObserver() = default;
479 public:
480 NS_DECL_ISUPPORTS
481 NS_DECL_NSIOBSERVER
484 NS_IMPL_ISUPPORTS(MemoryPressureObserver, nsIObserver)
486 NS_IMETHODIMP
487 MemoryPressureObserver::Observe(nsISupports *aSubject,
488 const char *aTopic,
489 const char16_t *someData)
491 NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic");
492 Factory::PurgeAllCaches();
493 gfxGradientCache::PurgeAllCaches();
495 gfxPlatform::PurgeSkiaFontCache();
496 gfxPlatform::GetPlatform()->PurgeSkiaGPUCache();
497 return NS_OK;
500 gfxPlatform::gfxPlatform()
501 : mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
502 , mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo)
503 , mTilesInfoCollector(this, &gfxPlatform::GetTilesSupportInfo)
504 , mCompositorBackend(layers::LayersBackend::LAYERS_NONE)
505 , mScreenDepth(0)
507 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
508 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
510 mWordCacheCharLimit = UNINITIALIZED_VALUE;
511 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
512 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
513 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
514 mBidiNumeralOption = UNINITIALIZED_VALUE;
516 mSkiaGlue = nullptr;
518 InitBackendPrefs(GetBackendPrefs());
520 mTotalSystemMemory = PR_GetPhysicalMemorySize();
522 VRManager::ManagerInit();
525 gfxPlatform*
526 gfxPlatform::GetPlatform()
528 if (!gPlatform) {
529 MOZ_RELEASE_ASSERT(!XRE_IsContentProcess(),
530 "Content Process should have called InitChild() before first GetPlatform()");
531 Init();
533 return gPlatform;
536 bool
537 gfxPlatform::Initialized()
539 return !!gPlatform;
542 /* static */ void
543 gfxPlatform::InitChild(const ContentDeviceData& aData)
545 MOZ_ASSERT(XRE_IsContentProcess());
546 MOZ_RELEASE_ASSERT(!gPlatform,
547 "InitChild() should be called before first GetPlatform()");
548 // Make the provided initial ContentDeviceData available to the init
549 // routines, so they don't have to do a sync request from the parent.
550 gContentDeviceInitData = &aData;
551 Init();
552 gContentDeviceInitData = nullptr;
555 void RecordingPrefChanged(const char *aPrefName, void *aClosure)
557 if (Preferences::GetBool("gfx.2d.recording", false)) {
558 nsAutoCString fileName;
559 nsAutoString prefFileName;
560 nsresult rv = Preferences::GetString("gfx.2d.recordingfile", prefFileName);
561 if (NS_SUCCEEDED(rv)) {
562 CopyUTF16toUTF8(prefFileName, fileName);
563 } else {
564 nsCOMPtr<nsIFile> tmpFile;
565 if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) {
566 return;
568 fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid());
570 nsresult rv = tmpFile->AppendNative(fileName);
571 if (NS_FAILED(rv))
572 return;
574 #ifdef XP_WIN
575 rv = tmpFile->GetPath(prefFileName);
576 CopyUTF16toUTF8(prefFileName, fileName);
577 #else
578 rv = tmpFile->GetNativePath(fileName);
579 #endif
580 if (NS_FAILED(rv))
581 return;
584 #ifdef XP_WIN
585 gPlatform->mRecorder = Factory::CreateEventRecorderForFile(prefFileName.BeginReading());
586 #else
587 gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading());
588 #endif
589 printf_stderr("Recording to %s\n", fileName.get());
590 Factory::SetGlobalEventRecorder(gPlatform->mRecorder);
591 } else {
592 Factory::SetGlobalEventRecorder(nullptr);
596 #define WR_DEBUG_PREF "gfx.webrender.debug"
598 void
599 WebRenderDebugPrefChangeCallback(const char* aPrefName, void*)
601 int32_t flags = 0;
602 #define GFX_WEBRENDER_DEBUG(suffix, bit) \
603 if (Preferences::GetBool(WR_DEBUG_PREF suffix, false)) { \
604 flags |= (bit); \
607 // TODO: It would be nice to get the bit patterns directly from the rust code.
608 GFX_WEBRENDER_DEBUG(".profiler", 1 << 0)
609 GFX_WEBRENDER_DEBUG(".render-targets", 1 << 1)
610 GFX_WEBRENDER_DEBUG(".texture-cache", 1 << 2)
611 GFX_WEBRENDER_DEBUG(".gpu-time-queries", 1 << 3)
612 GFX_WEBRENDER_DEBUG(".gpu-sample-queries", 1 << 4)
613 GFX_WEBRENDER_DEBUG(".disable-batching", 1 << 5)
614 GFX_WEBRENDER_DEBUG(".epochs", 1 << 6)
615 GFX_WEBRENDER_DEBUG(".compact-profiler", 1 << 7)
616 #undef GFX_WEBRENDER_DEBUG
618 gfx::gfxVars::SetWebRenderDebugFlags(flags);
622 #if defined(USE_SKIA)
623 static uint32_t GetSkiaGlyphCacheSize()
625 // Only increase font cache size on non-android to save memory.
626 #if !defined(MOZ_WIDGET_ANDROID)
627 // 10mb as the default pref cache size on desktop due to talos perf tweaking.
628 // Chromium uses 20mb and skia default uses 2mb.
629 // We don't need to change the font cache count since we usually
630 // cache thrash due to asian character sets in talos.
631 // Only increase memory on the content proces
632 uint32_t cacheSize = gfxPrefs::SkiaContentFontCacheSize() * 1024 * 1024;
633 if (mozilla::BrowserTabsRemoteAutostart()) {
634 return XRE_IsContentProcess() ? cacheSize : kDefaultGlyphCacheSize;
637 return cacheSize;
638 #else
639 return kDefaultGlyphCacheSize;
640 #endif // MOZ_WIDGET_ANDROID
642 #endif
644 void
645 gfxPlatform::Init()
647 MOZ_RELEASE_ASSERT(!XRE_IsGPUProcess(), "GFX: Not allowed in GPU process.");
648 MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
650 if (gEverInitialized) {
651 MOZ_CRASH("Already started???");
653 gEverInitialized = true;
655 // Initialize the preferences by creating the singleton.
656 gfxPrefs::GetSingleton();
657 MediaPrefs::GetSingleton();
658 gfxVars::Initialize();
660 gfxConfig::Init();
662 if (XRE_IsParentProcess()) {
663 GPUProcessManager::Initialize();
665 if (Preferences::GetBool("media.wmf.skip-blacklist")) {
666 gfxVars::SetPDMWMFDisableD3D11Dlls(nsCString());
667 gfxVars::SetPDMWMFDisableD3D9Dlls(nsCString());
668 } else {
669 nsAutoCString d3d11;
670 Preferences::GetCString("media.wmf.disable-d3d11-for-dlls", d3d11);
671 gfxVars::SetPDMWMFDisableD3D11Dlls(d3d11);
672 nsAutoCString d3d9;
673 Preferences::GetCString("media.wmf.disable-d3d9-for-dlls", d3d9);
674 gfxVars::SetPDMWMFDisableD3D9Dlls(d3d9);
677 nsCOMPtr<nsIFile> file;
678 nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
679 if (NS_FAILED(rv)) {
680 gfxVars::SetGREDirectory(nsString());
681 } else {
682 nsAutoString path;
683 file->GetPath(path);
684 gfxVars::SetGREDirectory(nsString(path));
688 // Drop a note in the crash report if we end up forcing an option that could
689 // destabilize things. New items should be appended at the end (of an existing
690 // or in a new section), so that we don't have to know the version to interpret
691 // these cryptic strings.
693 nsAutoCString forcedPrefs;
694 // D2D prefs
695 forcedPrefs.AppendPrintf("FP(D%d%d",
696 gfxPrefs::Direct2DDisabled(),
697 gfxPrefs::Direct2DForceEnabled());
698 // Layers prefs
699 forcedPrefs.AppendPrintf("-L%d%d%d%d",
700 gfxPrefs::LayersAMDSwitchableGfxEnabled(),
701 gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly(),
702 gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly(),
703 gfxPrefs::LayersD3D11ForceWARP());
704 // WebGL prefs
705 forcedPrefs.AppendPrintf("-W%d%d%d%d%d%d%d%d",
706 gfxPrefs::WebGLANGLEForceD3D11(),
707 gfxPrefs::WebGLANGLEForceWARP(),
708 gfxPrefs::WebGLDisabled(),
709 gfxPrefs::WebGLDisableANGLE(),
710 gfxPrefs::WebGLDXGLEnabled(),
711 gfxPrefs::WebGLForceEnabled(),
712 gfxPrefs::WebGLForceLayersReadback(),
713 gfxPrefs::WebGLForceMSAA());
714 // Prefs that don't fit into any of the other sections
715 forcedPrefs.AppendPrintf("-T%d%d%d) ",
716 gfxPrefs::AndroidRGB16Force(),
717 gfxPrefs::CanvasAzureAccelerated(),
718 gfxPrefs::ForceShmemTiles());
719 ScopedGfxFeatureReporter::AppNote(forcedPrefs);
722 InitMoz2DLogging();
724 gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
726 /* Initialize the GfxInfo service.
727 * Note: we can't call functions on GfxInfo that depend
728 * on gPlatform until after it has been initialized
729 * below. GfxInfo initialization annotates our
730 * crash reports so we want to do it before
731 * we try to load any drivers and do device detection
732 * incase that code crashes. See bug #591561. */
733 nsCOMPtr<nsIGfxInfo> gfxInfo;
734 /* this currently will only succeed on Windows */
735 gfxInfo = services::GetGfxInfo();
737 #if defined(XP_WIN)
738 gPlatform = new gfxWindowsPlatform;
739 #elif defined(XP_MACOSX)
740 gPlatform = new gfxPlatformMac;
741 #elif defined(MOZ_WIDGET_GTK)
742 gPlatform = new gfxPlatformGtk;
743 #elif defined(ANDROID)
744 gPlatform = new gfxAndroidPlatform;
745 #else
746 #error "No gfxPlatform implementation available"
747 #endif
748 gPlatform->InitAcceleration();
749 gPlatform->InitWebRenderConfig();
750 gPlatform->InitOMTPConfig();
752 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
753 GPUProcessManager* gpu = GPUProcessManager::Get();
754 gpu->LaunchGPUProcess();
757 if (XRE_IsParentProcess()) {
758 if (gfxPlatform::ForceSoftwareVsync()) {
759 gPlatform->mVsyncSource = (gPlatform)->gfxPlatform::CreateHardwareVsyncSource();
760 } else {
761 gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource();
765 #ifdef USE_SKIA
766 SkGraphics::Init();
767 # ifdef MOZ_ENABLE_FREETYPE
768 SkInitCairoFT(gPlatform->FontHintingEnabled());
769 # endif
770 #endif
772 InitLayersIPC();
774 gPlatform->PopulateScreenInfo();
775 gPlatform->ComputeTileSize();
777 nsresult rv;
778 rv = gfxPlatformFontList::Init();
779 if (NS_FAILED(rv)) {
780 MOZ_CRASH("Could not initialize gfxPlatformFontList");
783 gPlatform->mScreenReferenceSurface =
784 gPlatform->CreateOffscreenSurface(IntSize(1, 1),
785 SurfaceFormat::A8R8G8B8_UINT32);
786 if (!gPlatform->mScreenReferenceSurface) {
787 MOZ_CRASH("Could not initialize mScreenReferenceSurface");
790 gPlatform->mScreenReferenceDrawTarget =
791 gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
792 SurfaceFormat::B8G8R8A8);
793 if (!gPlatform->mScreenReferenceDrawTarget ||
794 !gPlatform->mScreenReferenceDrawTarget->IsValid()) {
795 // If TDR is detected, create a draw target with software backend
796 // and it should be replaced later when the process gets the device
797 // reset notification.
798 if (!gPlatform->DidRenderingDeviceReset()) {
799 gfxCriticalError() << "Could not initialize mScreenReferenceDrawTarget";
803 rv = gfxFontCache::Init();
804 if (NS_FAILED(rv)) {
805 MOZ_CRASH("Could not initialize gfxFontCache");
808 #ifdef MOZ_ENABLE_FREETYPE
809 Factory::SetFTLibrary(gPlatform->GetFTLibrary());
810 #endif
812 /* Create and register our CMS Override observer. */
813 gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
814 Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
816 gPlatform->mFontPrefsObserver = new FontPrefsObserver();
817 Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
819 GLContext::PlatformStartup();
821 Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording");
823 CreateCMSOutputProfile();
825 // Listen to memory pressure event so we can purge DrawTarget caches
826 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
827 if (obs) {
828 gPlatform->mMemoryPressureObserver = new MemoryPressureObserver();
829 obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false);
832 // Request the imgITools service, implicitly initializing ImageLib.
833 nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
834 if (!imgTools) {
835 MOZ_CRASH("Could not initialize ImageLib");
838 RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
839 mlg::InitializeMemoryReporters();
841 #ifdef USE_SKIA
842 uint32_t skiaCacheSize = GetSkiaGlyphCacheSize();
843 if (skiaCacheSize != kDefaultGlyphCacheSize) {
844 SkGraphics::SetFontCacheLimit(skiaCacheSize);
846 #endif
848 InitNullMetadata();
849 InitOpenGLConfig();
851 if (XRE_IsParentProcess()) {
852 gfxVars::SetDXInterop2Blocked(IsDXInterop2Blocked());
855 if (obs) {
856 obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr);
860 /* static*/ bool
861 gfxPlatform::IsDXInterop2Blocked()
863 nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
864 nsCString blockId;
865 int32_t status;
866 if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DX_INTEROP2,
867 blockId, &status))) {
868 return true;
870 return status != nsIGfxInfo::FEATURE_STATUS_OK;
873 /* static */ int32_t
874 gfxPlatform::MaxTextureSize()
876 // Make sure we don't completely break rendering because of a typo in the
877 // pref or whatnot.
878 const int32_t kMinSizePref = 2048;
879 return std::max(kMinSizePref, gfxPrefs::MaxTextureSizeDoNotUseDirectly());
882 /* static */ int32_t
883 gfxPlatform::MaxAllocSize()
885 // Make sure we don't completely break rendering because of a typo in the
886 // pref or whatnot.
887 const int32_t kMinAllocPref = 10000000;
888 return std::max(kMinAllocPref, gfxPrefs::MaxAllocSizeDoNotUseDirectly());
891 /* static */ void
892 gfxPlatform::InitMoz2DLogging()
894 auto fwd = new CrashStatsLogForwarder("GraphicsCriticalError");
895 fwd->SetCircularBufferSize(gfxPrefs::GfxLoggingCrashLength());
897 mozilla::gfx::Config cfg;
898 cfg.mLogForwarder = fwd;
899 cfg.mMaxTextureSize = gfxPlatform::MaxTextureSize();
900 cfg.mMaxAllocSize = gfxPlatform::MaxAllocSize();
902 gfx::Factory::Init(cfg);
905 /* static */ bool
906 gfxPlatform::IsHeadless()
908 static bool initialized = false;
909 static bool headless = false;
910 if (!initialized) {
911 initialized = true;
912 headless = PR_GetEnv("MOZ_HEADLESS");
914 return headless;
917 static bool sLayersIPCIsUp = false;
919 /* static */ void
920 gfxPlatform::InitNullMetadata()
922 ScrollMetadata::sNullMetadata = new ScrollMetadata();
923 ClearOnShutdown(&ScrollMetadata::sNullMetadata);
926 void
927 gfxPlatform::Shutdown()
929 // In some cases, gPlatform may not be created but Shutdown() called,
930 // e.g., during xpcshell tests.
931 if (!gPlatform) {
932 return;
935 MOZ_ASSERT(!sLayersIPCIsUp);
937 // These may be called before the corresponding subsystems have actually
938 // started up. That's OK, they can handle it.
939 gfxFontCache::Shutdown();
940 gfxGradientCache::Shutdown();
941 gfxAlphaBoxBlur::ShutdownBlurCache();
942 gfxGraphiteShaper::Shutdown();
943 gfxPlatformFontList::Shutdown();
944 ShutdownTileCache();
946 // Free the various non-null transforms and loaded profiles
947 ShutdownCMS();
949 /* Unregister our CMS Override callback. */
950 NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone");
951 Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
952 gPlatform->mSRGBOverrideObserver = nullptr;
954 NS_ASSERTION(gPlatform->mFontPrefsObserver, "mFontPrefsObserver has alreay gone");
955 Preferences::RemoveObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
956 gPlatform->mFontPrefsObserver = nullptr;
958 NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone");
959 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
960 if (obs) {
961 obs->RemoveObserver(gPlatform->mMemoryPressureObserver, "memory-pressure");
964 gPlatform->mMemoryPressureObserver = nullptr;
965 gPlatform->mSkiaGlue = nullptr;
967 if (XRE_IsParentProcess()) {
968 gPlatform->mVsyncSource->Shutdown();
971 gPlatform->mVsyncSource = nullptr;
973 // Shut down the default GL context provider.
974 GLContextProvider::Shutdown();
976 #if defined(XP_WIN)
977 // The above shutdown calls operate on the available context providers on
978 // most platforms. Windows is a "special snowflake", though, and has three
979 // context providers available, so we have to shut all of them down.
980 // We should only support the default GL provider on Windows; then, this
981 // could go away. Unfortunately, we currently support WGL (the default) for
982 // WebGL on Optimus.
983 GLContextProviderEGL::Shutdown();
984 #endif
986 if (XRE_IsParentProcess()) {
987 GPUProcessManager::Shutdown();
990 gfx::Factory::ShutDown();
992 delete gGfxPlatformPrefsLock;
994 gfxVars::Shutdown();
995 gfxPrefs::DestroySingleton();
996 gfxFont::DestroySingletons();
998 gfxConfig::Shutdown();
1000 gPlatform->WillShutdown();
1002 delete gPlatform;
1003 gPlatform = nullptr;
1006 /* static */ void
1007 gfxPlatform::InitLayersIPC()
1009 if (sLayersIPCIsUp) {
1010 return;
1012 sLayersIPCIsUp = true;
1014 if (gfxVars::UseWebRender()) {
1015 wr::WebRenderAPI::InitExternalLogHandler();
1018 if (XRE_IsContentProcess()) {
1019 if (gfxVars::UseOMTP()) {
1020 layers::PaintThread::Start();
1022 } else if (XRE_IsParentProcess()) {
1023 if (gfxVars::UseWebRender()) {
1024 wr::RenderThread::Start();
1025 layers::SharedSurfacesParent::Initialize();
1028 layers::CompositorThreadHolder::Start();
1029 gfx::VRListenerThreadHolder::Start();
1033 /* static */ void
1034 gfxPlatform::ShutdownLayersIPC()
1036 if (!sLayersIPCIsUp) {
1037 return;
1039 sLayersIPCIsUp = false;
1041 if (XRE_IsContentProcess()) {
1042 gfx::VRManagerChild::ShutDown();
1043 // cf bug 1215265.
1044 if (gfxPrefs::ChildProcessShutdown()) {
1045 layers::CompositorManagerChild::Shutdown();
1046 layers::ImageBridgeChild::ShutDown();
1049 if (gfxVars::UseOMTP()) {
1050 layers::PaintThread::Shutdown();
1052 } else if (XRE_IsParentProcess()) {
1053 gfx::VRManagerChild::ShutDown();
1054 layers::CompositorManagerChild::Shutdown();
1055 layers::ImageBridgeChild::ShutDown();
1056 // This has to happen after shutting down the child protocols.
1057 layers::CompositorThreadHolder::Shutdown();
1058 gfx::VRListenerThreadHolder::Shutdown();
1059 // There is a case that RenderThread exists when gfxVars::UseWebRender() is false.
1060 // This could happen when WebRender was fallbacked to compositor.
1061 if (wr::RenderThread::Get()) {
1062 layers::SharedSurfacesParent::Shutdown();
1063 wr::RenderThread::ShutDown();
1065 Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF);
1068 } else {
1069 // TODO: There are other kind of processes and we should make sure gfx
1070 // stuff is either not created there or shut down properly.
1073 if (gfxVars::UseWebRender()) {
1074 wr::WebRenderAPI::ShutdownExternalLogHandler();
1078 void
1079 gfxPlatform::WillShutdown()
1081 // Destoy these first in case they depend on backend-specific resources.
1082 // Otherwise, the backend's destructor would be called before the
1083 // base gfxPlatform destructor.
1084 mScreenReferenceSurface = nullptr;
1085 mScreenReferenceDrawTarget = nullptr;
1088 gfxPlatform::~gfxPlatform()
1090 // The cairo folks think we should only clean up in debug builds,
1091 // but we're generally in the habit of trying to shut down as
1092 // cleanly as possible even in production code, so call this
1093 // cairo_debug_* function unconditionally.
1095 // because cairo can assert and thus crash on shutdown, don't do this in release builds
1096 #ifdef NS_FREE_PERMANENT_DATA
1097 #ifdef USE_SKIA
1098 // must do Skia cleanup before Cairo cleanup, because Skia may be referencing
1099 // Cairo objects e.g. through SkCairoFTTypeface
1100 SkGraphics::PurgeFontCache();
1101 #endif
1103 #if MOZ_TREE_CAIRO
1104 cairo_debug_reset_static_data();
1105 #endif
1106 #endif
1109 /* static */ already_AddRefed<DrawTarget>
1110 gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize)
1112 SurfaceFormat format = aSurface->GetSurfaceFormat();
1113 RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format);
1114 if (!drawTarget) {
1115 gfxWarning() << "gfxPlatform::CreateDrawTargetForSurface failed in CreateDrawTargetForCairoSurface";
1116 return nullptr;
1118 return drawTarget.forget();
1121 cairo_user_data_key_t kSourceSurface;
1124 * Record the backend that was used to construct the SourceSurface.
1125 * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
1126 * we check to make sure the DrawTarget's backend matches the backend
1127 * for the cached SourceSurface, and only use it if they match. This
1128 * can avoid expensive and unnecessary readbacks.
1130 struct SourceSurfaceUserData
1132 RefPtr<SourceSurface> mSrcSurface;
1133 BackendType mBackendType;
1136 void SourceBufferDestroy(void *srcSurfUD)
1138 delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
1141 UserDataKey kThebesSurface;
1143 struct DependentSourceSurfaceUserData
1145 RefPtr<gfxASurface> mSurface;
1148 void SourceSurfaceDestroyed(void *aData)
1150 delete static_cast<DependentSourceSurfaceUserData*>(aData);
1153 void
1154 gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
1156 aSurface->SetData(&kSourceSurface, nullptr, nullptr);
1159 /* static */ already_AddRefed<SourceSurface>
1160 gfxPlatform::GetSourceSurfaceForSurface(RefPtr<DrawTarget> aTarget,
1161 gfxASurface* aSurface,
1162 bool aIsPlugin)
1164 if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
1165 return nullptr;
1168 if (!aTarget) {
1169 aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
1172 void *userData = aSurface->GetData(&kSourceSurface);
1174 if (userData) {
1175 SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData);
1177 if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetBackendType()) {
1178 RefPtr<SourceSurface> srcSurface(surf->mSrcSurface);
1179 return srcSurface.forget();
1181 // We can just continue here as when setting new user data the destroy
1182 // function will be called for the old user data.
1185 SurfaceFormat format = aSurface->GetSurfaceFormat();
1187 if (aTarget->GetBackendType() == BackendType::CAIRO) {
1188 // If we're going to be used with a CAIRO DrawTarget, then just create a
1189 // SourceSurfaceCairo since we don't know the underlying type of the CAIRO
1190 // DrawTarget and can't pick a better surface type. Doing this also avoids
1191 // readback of aSurface's surface into memory if, for example, aSurface
1192 // wraps an xlib cairo surface (which can be important to avoid a major
1193 // slowdown).
1195 // We return here regardless of whether CreateSourceSurfaceFromNativeSurface
1196 // succeeds or not since we don't expect to be able to do any better below
1197 // if it fails.
1199 // Note that the returned SourceSurfaceCairo holds a strong reference to
1200 // the cairo_surface_t* that it wraps, which essencially means it holds a
1201 // strong reference to aSurface since aSurface shares its
1202 // cairo_surface_t*'s reference count variable. As a result we can't cache
1203 // srcBuffer on aSurface (see below) since aSurface would then hold a
1204 // strong reference back to srcBuffer, creating a reference loop and a
1205 // memory leak. Not caching is fine since wrapping is cheap enough (no
1206 // copying) so we can just wrap again next time we're called.
1207 return Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(),
1208 aSurface->GetSize(), format);
1211 RefPtr<SourceSurface> srcBuffer;
1213 // Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface
1215 if (!srcBuffer) {
1216 // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
1217 // the same data, then optimize it for aTarget:
1218 RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface);
1219 if (surf) {
1220 srcBuffer = aIsPlugin ? aTarget->OptimizeSourceSurfaceForUnknownAlpha(surf)
1221 : aTarget->OptimizeSourceSurface(surf);
1223 if (srcBuffer == surf) {
1224 // GetWrappedDataSourceSurface returns a SourceSurface that holds a
1225 // strong reference to aSurface since it wraps aSurface's data and
1226 // needs it to stay alive. As a result we can't cache srcBuffer on
1227 // aSurface (below) since aSurface would then hold a strong reference
1228 // back to srcBuffer, creating a reference loop and a memory leak. Not
1229 // caching is fine since wrapping is cheap enough (no copying) so we
1230 // can just wrap again next time we're called.
1232 // Note that the check below doesn't catch this since srcBuffer will be a
1233 // SourceSurfaceRawData object (even if aSurface is not a gfxImageSurface
1234 // object), which is why we need this separate check.
1235 return srcBuffer.forget();
1240 if (!srcBuffer) {
1241 MOZ_ASSERT(aTarget->GetBackendType() != BackendType::CAIRO,
1242 "We already tried CreateSourceSurfaceFromNativeSurface with a "
1243 "DrawTargetCairo above");
1244 // We've run out of performant options. We now try creating a SourceSurface
1245 // using a temporary DrawTargetCairo and then optimizing it to aTarget's
1246 // actual type. The CreateSourceSurfaceFromNativeSurface() call will
1247 // likely create a DataSourceSurface (possibly involving copying and/or
1248 // readback), and the OptimizeSourceSurface may well copy again and upload
1249 // to the GPU. So, while this code path is rarely hit, hitting it may be
1250 // very slow.
1251 srcBuffer = Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(),
1252 aSurface->GetSize(), format);
1253 if (srcBuffer) {
1254 srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer);
1258 if (!srcBuffer) {
1259 return nullptr;
1262 if ((srcBuffer->GetType() == SurfaceType::CAIRO &&
1263 static_cast<SourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1264 aSurface->CairoSurface()) ||
1265 (srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE &&
1266 static_cast<DataSourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
1267 aSurface->CairoSurface())) {
1268 // See the "Note that the returned SourceSurfaceCairo..." comment above.
1269 return srcBuffer.forget();
1272 // Add user data to aSurface so we can cache lookups in the future.
1273 auto *srcSurfUD = new SourceSurfaceUserData;
1274 srcSurfUD->mBackendType = aTarget->GetBackendType();
1275 srcSurfUD->mSrcSurface = srcBuffer;
1276 aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
1278 return srcBuffer.forget();
1281 already_AddRefed<DataSourceSurface>
1282 gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
1284 RefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
1285 if (!image) {
1286 return nullptr;
1288 RefPtr<DataSourceSurface> result =
1289 Factory::CreateWrappingDataSourceSurface(image->Data(),
1290 image->Stride(),
1291 image->GetSize(),
1292 ImageFormatToSurfaceFormat(image->Format()));
1294 if (!result) {
1295 return nullptr;
1298 // If we wrapped the underlying data of aSurface, then we need to add user data
1299 // to make sure aSurface stays alive until we are done with the data.
1300 auto *srcSurfUD = new DependentSourceSurfaceUserData;
1301 srcSurfUD->mSurface = aSurface;
1302 result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
1304 return result.forget();
1307 void
1308 gfxPlatform::ComputeTileSize()
1310 // The tile size should be picked in the parent processes
1311 // and sent to the child processes over IPDL GetTileSize.
1312 if (!XRE_IsParentProcess()) {
1313 return;
1316 int32_t w = gfxPrefs::LayersTileWidth();
1317 int32_t h = gfxPrefs::LayersTileHeight();
1319 if (gfxPrefs::LayersTilesAdjust()) {
1320 gfx::IntSize screenSize = GetScreenSize();
1321 if (screenSize.width > 0) {
1322 // Choose a size so that there are between 2 and 4 tiles per screen width.
1323 // FIXME: we should probably make sure this is within the max texture size,
1324 // but I think everything should at least support 1024
1325 w = h = clamped(int32_t(RoundUpPow2(screenSize.width)) / 4, 256, 1024);
1329 // Don't allow changing the tile size after we've set it.
1330 // Right now the code assumes that the tile size doesn't change.
1331 MOZ_ASSERT(gfxVars::TileSize().width == -1 &&
1332 gfxVars::TileSize().height == -1);
1334 gfxVars::SetTileSize(IntSize(w, h));
1337 void
1338 gfxPlatform::PopulateScreenInfo()
1340 nsCOMPtr<nsIScreenManager> manager = do_GetService("@mozilla.org/gfx/screenmanager;1");
1341 MOZ_ASSERT(manager, "failed to get nsIScreenManager");
1343 nsCOMPtr<nsIScreen> screen;
1344 manager->GetPrimaryScreen(getter_AddRefs(screen));
1345 if (!screen) {
1346 // This can happen in xpcshell, for instance
1347 return;
1350 screen->GetColorDepth(&mScreenDepth);
1351 if (XRE_IsParentProcess()) {
1352 gfxVars::SetScreenDepth(mScreenDepth);
1355 int left, top;
1356 screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height);
1359 bool
1360 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
1362 if (!aTarget || !aTarget->IsValid()) {
1363 return false;
1366 #ifdef USE_SKIA_GPU
1367 // Skia content rendering doesn't support GPU acceleration, so we can't
1368 // use the same backend if the current backend is accelerated.
1369 if ((aTarget->GetType() == DrawTargetType::HARDWARE_RASTER)
1370 && (aTarget->GetBackendType() == BackendType::SKIA))
1372 return false;
1374 #endif
1376 return SupportsAzureContentForType(aTarget->GetBackendType());
1379 bool gfxPlatform::AllowOpenGLCanvas()
1381 // For now, only allow Skia+OpenGL, unless it's blocked.
1382 // Allow acceleration on Skia if the preference is set, unless it's blocked
1383 // as long as we have the accelerated layers
1385 // The compositor backend is only set correctly in the parent process,
1386 // so we let content process always assume correct compositor backend.
1387 // The callers have to do the right thing.
1388 bool correctBackend = !XRE_IsParentProcess() ||
1389 ((mCompositorBackend == LayersBackend::LAYERS_OPENGL ||
1390 mCompositorBackend == LayersBackend::LAYERS_WR) &&
1391 (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA));
1393 if (gfxPrefs::CanvasAzureAccelerated() && correctBackend) {
1394 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
1395 int32_t status;
1396 nsCString discardFailureId;
1397 return !gfxInfo ||
1398 (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION,
1399 discardFailureId,
1400 &status)) &&
1401 status == nsIGfxInfo::FEATURE_STATUS_OK);
1403 return false;
1406 void
1407 gfxPlatform::InitializeSkiaCacheLimits()
1409 if (AllowOpenGLCanvas()) {
1410 #ifdef USE_SKIA_GPU
1411 bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
1412 int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
1413 uint64_t cacheSizeLimit = std::max(gfxPrefs::CanvasSkiaGLCacheSize(), (int32_t)0);
1415 // Prefs are in megabytes, but we want the sizes in bytes
1416 cacheSizeLimit *= 1024*1024;
1418 if (usingDynamicCache) {
1419 if (mTotalSystemMemory < 512*1024*1024) {
1420 // We need a very minimal cache on anything smaller than 512mb.
1421 // Note the large jump as we cross 512mb (from 2mb to 32mb).
1422 cacheSizeLimit = 2*1024*1024;
1423 } else if (mTotalSystemMemory > 0) {
1424 cacheSizeLimit = mTotalSystemMemory / 16;
1428 // Ensure cache size doesn't overflow on 32-bit platforms.
1429 cacheSizeLimit = std::min(cacheSizeLimit, (uint64_t)SIZE_MAX);
1431 #ifdef DEBUG
1432 printf_stderr("Determined SkiaGL cache limits: Size %" PRIu64 ", Items: %i\n", cacheSizeLimit, cacheItemLimit);
1433 #endif
1435 mSkiaGlue->GetGrContext()->setResourceCacheLimits(cacheItemLimit, (size_t)cacheSizeLimit);
1436 #endif
1440 SkiaGLGlue*
1441 gfxPlatform::GetSkiaGLGlue()
1443 #ifdef USE_SKIA_GPU
1444 // Check the accelerated Canvas is enabled for the first time,
1445 // because the callers should check it before using.
1446 if (!mSkiaGlue && !AllowOpenGLCanvas()) {
1447 return nullptr;
1450 if (!mSkiaGlue) {
1451 /* Dummy context. We always draw into a FBO.
1453 * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
1454 * stands, this only works on the main thread.
1456 RefPtr<GLContext> glContext;
1457 nsCString discardFailureId;
1458 glContext = GLContextProvider::CreateHeadless(CreateContextFlags::REQUIRE_COMPAT_PROFILE |
1459 CreateContextFlags::ALLOW_OFFLINE_RENDERER,
1460 &discardFailureId);
1461 if (!glContext) {
1462 printf_stderr("Failed to create GLContext for SkiaGL!\n");
1463 return nullptr;
1465 mSkiaGlue = new SkiaGLGlue(glContext);
1466 MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext");
1467 InitializeSkiaCacheLimits();
1469 #endif
1471 return mSkiaGlue;
1474 void
1475 gfxPlatform::PurgeSkiaFontCache()
1477 #ifdef USE_SKIA
1478 if (gfxPlatform::GetPlatform()->GetDefaultContentBackend() == BackendType::SKIA) {
1479 SkGraphics::PurgeFontCache();
1481 #endif
1484 void
1485 gfxPlatform::PurgeSkiaGPUCache()
1487 #ifdef USE_SKIA_GPU
1488 if (!mSkiaGlue)
1489 return;
1491 mSkiaGlue->GetGrContext()->freeGpuResources();
1492 // GrContext::flush() doesn't call glFlush. Call it here.
1493 mSkiaGlue->GetGLContext()->MakeCurrent();
1494 mSkiaGlue->GetGLContext()->fFlush();
1495 #endif
1498 bool
1499 gfxPlatform::HasEnoughTotalSystemMemoryForSkiaGL()
1501 return true;
1504 already_AddRefed<DrawTarget>
1505 gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
1507 // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
1508 // create the best offscreen surface for the current system and situation. We
1509 // can easily take advantage of this for the Cairo backend, so that's what we
1510 // do.
1511 // mozilla::gfx::Factory can get away without having all this knowledge for
1512 // now, but this might need to change in the future (using
1513 // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
1514 // backends).
1515 if (aBackend == BackendType::CAIRO) {
1516 RefPtr<gfxASurface> surf = CreateOffscreenSurface(aSize, SurfaceFormatToImageFormat(aFormat));
1517 if (!surf || surf->CairoStatus()) {
1518 return nullptr;
1520 return CreateDrawTargetForSurface(surf, aSize);
1522 return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
1525 already_AddRefed<DrawTarget>
1526 gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
1528 NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
1529 RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
1530 if (target ||
1531 mFallbackCanvasBackend == BackendType::NONE) {
1532 return target.forget();
1535 #ifdef XP_WIN
1536 // On Windows, the fallback backend (Cairo) should use its image backend.
1537 return Factory::CreateDrawTarget(mFallbackCanvasBackend, aSize, aFormat);
1538 #else
1539 return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
1540 #endif
1543 already_AddRefed<DrawTarget>
1544 gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize,
1545 SurfaceFormat aFormat,
1546 bool aFallback)
1548 BackendType backend = (aFallback) ? mSoftwareBackend : mContentBackend;
1549 NS_ASSERTION(backend != BackendType::NONE, "No backend.");
1550 return CreateDrawTargetForBackend(backend, aSize, aFormat);
1553 already_AddRefed<DrawTarget>
1554 gfxPlatform::CreateSimilarSoftwareDrawTarget(DrawTarget* aDT,
1555 const IntSize& aSize,
1556 SurfaceFormat aFormat)
1558 RefPtr<DrawTarget> dt;
1560 if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) {
1561 dt = aDT->CreateSimilarDrawTarget(aSize, aFormat);
1562 } else {
1563 #ifdef USE_SKIA
1564 BackendType backendType = BackendType::SKIA;
1565 #else
1566 BackendType backendType = BackendType::CAIRO;
1567 #endif
1568 dt = Factory::CreateDrawTarget(backendType, aSize, aFormat);
1571 return dt.forget();
1574 /* static */ already_AddRefed<DrawTarget>
1575 gfxPlatform::CreateDrawTargetForData(unsigned char* aData,
1576 const IntSize& aSize,
1577 int32_t aStride,
1578 SurfaceFormat aFormat,
1579 bool aUninitialized)
1581 BackendType backendType = gfxVars::ContentBackend();
1582 NS_ASSERTION(backendType != BackendType::NONE, "No backend.");
1584 if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) {
1585 #ifdef USE_SKIA
1586 backendType = BackendType::SKIA;
1587 #else
1588 backendType = BackendType::CAIRO;
1589 #endif
1592 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(backendType,
1593 aData, aSize,
1594 aStride, aFormat,
1595 aUninitialized);
1597 return dt.forget();
1600 /* static */ BackendType
1601 gfxPlatform::BackendTypeForName(const nsCString& aName)
1603 if (aName.EqualsLiteral("cairo"))
1604 return BackendType::CAIRO;
1605 if (aName.EqualsLiteral("skia"))
1606 return BackendType::SKIA;
1607 if (aName.EqualsLiteral("direct2d"))
1608 return BackendType::DIRECT2D;
1609 if (aName.EqualsLiteral("direct2d1.1"))
1610 return BackendType::DIRECT2D1_1;
1611 return BackendType::NONE;
1614 nsresult
1615 gfxPlatform::GetFontList(nsAtom *aLangGroup,
1616 const nsACString& aGenericFamily,
1617 nsTArray<nsString>& aListOfFonts)
1619 gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
1620 aGenericFamily,
1621 aListOfFonts);
1622 return NS_OK;
1625 nsresult
1626 gfxPlatform::UpdateFontList()
1628 gfxPlatformFontList::PlatformFontList()->UpdateFontList();
1629 return NS_OK;
1632 nsresult
1633 gfxPlatform::GetStandardFamilyName(const nsAString& aFontName,
1634 nsAString& aFamilyName)
1636 gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName,
1637 aFamilyName);
1638 return NS_OK;
1641 nsString
1642 gfxPlatform::GetDefaultFontName(const nsACString& aLangGroup,
1643 const nsACString& aGenericFamily)
1645 gfxFontFamily* fontFamily = gfxPlatformFontList::PlatformFontList()->
1646 GetDefaultFontFamily(aLangGroup, aGenericFamily);
1647 if (!fontFamily) {
1648 return EmptyString();
1650 nsAutoString result;
1651 fontFamily->LocalizedName(result);
1652 return result;
1655 bool
1656 gfxPlatform::DownloadableFontsEnabled()
1658 if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
1659 mAllowDownloadableFonts =
1660 Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
1663 return mAllowDownloadableFonts;
1666 bool
1667 gfxPlatform::UseCmapsDuringSystemFallback()
1669 if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
1670 mFallbackUsesCmaps =
1671 Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
1674 return mFallbackUsesCmaps;
1677 bool
1678 gfxPlatform::OpenTypeSVGEnabled()
1680 if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) {
1681 mOpenTypeSVGEnabled =
1682 Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false);
1685 return mOpenTypeSVGEnabled > 0;
1688 uint32_t
1689 gfxPlatform::WordCacheCharLimit()
1691 if (mWordCacheCharLimit == UNINITIALIZED_VALUE) {
1692 mWordCacheCharLimit =
1693 Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32);
1694 if (mWordCacheCharLimit < 0) {
1695 mWordCacheCharLimit = 32;
1699 return uint32_t(mWordCacheCharLimit);
1702 uint32_t
1703 gfxPlatform::WordCacheMaxEntries()
1705 if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) {
1706 mWordCacheMaxEntries =
1707 Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000);
1708 if (mWordCacheMaxEntries < 0) {
1709 mWordCacheMaxEntries = 10000;
1713 return uint32_t(mWordCacheMaxEntries);
1716 bool
1717 gfxPlatform::UseGraphiteShaping()
1719 if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) {
1720 mGraphiteShapingEnabled =
1721 Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
1724 return mGraphiteShapingEnabled;
1727 bool
1728 gfxPlatform::IsFontFormatSupported(uint32_t aFormatFlags)
1730 // check for strange format flags
1731 MOZ_ASSERT(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
1732 "strange font format hint set");
1734 // accept "common" formats that we support on all platforms
1735 if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
1736 return true;
1739 // reject all other formats, known and unknown
1740 if (aFormatFlags != 0) {
1741 return false;
1744 // no format hint set, need to look at data
1745 return true;
1748 gfxFontEntry*
1749 gfxPlatform::LookupLocalFont(const nsAString& aFontName,
1750 uint16_t aWeight,
1751 int16_t aStretch,
1752 uint8_t aStyle)
1754 return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aFontName,
1755 aWeight,
1756 aStretch,
1757 aStyle);
1760 gfxFontEntry*
1761 gfxPlatform::MakePlatformFont(const nsAString& aFontName,
1762 uint16_t aWeight,
1763 int16_t aStretch,
1764 uint8_t aStyle,
1765 const uint8_t* aFontData,
1766 uint32_t aLength)
1768 return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aFontName,
1769 aWeight,
1770 aStretch,
1771 aStyle,
1772 aFontData,
1773 aLength);
1776 mozilla::layers::DiagnosticTypes
1777 gfxPlatform::GetLayerDiagnosticTypes()
1779 mozilla::layers::DiagnosticTypes type = DiagnosticTypes::NO_DIAGNOSTIC;
1780 if (gfxPrefs::DrawLayerBorders()) {
1781 type |= mozilla::layers::DiagnosticTypes::LAYER_BORDERS;
1783 if (gfxPrefs::DrawTileBorders()) {
1784 type |= mozilla::layers::DiagnosticTypes::TILE_BORDERS;
1786 if (gfxPrefs::DrawBigImageBorders()) {
1787 type |= mozilla::layers::DiagnosticTypes::BIGIMAGE_BORDERS;
1789 if (gfxPrefs::FlashLayerBorders()) {
1790 type |= mozilla::layers::DiagnosticTypes::FLASH_BORDERS;
1792 return type;
1795 BackendPrefsData
1796 gfxPlatform::GetBackendPrefs()
1798 BackendPrefsData data;
1800 data.mCanvasBitmask = BackendTypeBit(BackendType::CAIRO);
1801 data.mContentBitmask = BackendTypeBit(BackendType::CAIRO);
1802 #ifdef USE_SKIA
1803 data.mCanvasBitmask |= BackendTypeBit(BackendType::SKIA);
1804 data.mContentBitmask |= BackendTypeBit(BackendType::SKIA);
1805 #endif
1806 data.mCanvasDefault = BackendType::CAIRO;
1807 data.mContentDefault = BackendType::CAIRO;
1809 return mozilla::Move(data);
1812 void
1813 gfxPlatform::InitBackendPrefs(BackendPrefsData&& aPrefsData)
1815 mPreferredCanvasBackend = GetCanvasBackendPref(aPrefsData.mCanvasBitmask);
1816 if (mPreferredCanvasBackend == BackendType::NONE) {
1817 mPreferredCanvasBackend = aPrefsData.mCanvasDefault;
1820 if (mPreferredCanvasBackend == BackendType::DIRECT2D1_1) {
1821 // Falling back to D2D 1.0 won't help us here. When D2D 1.1 DT creation
1822 // fails it means the surface was too big or there's something wrong with
1823 // the device. D2D 1.0 will encounter a similar situation.
1824 mFallbackCanvasBackend =
1825 GetCanvasBackendPref(aPrefsData.mCanvasBitmask &
1826 ~(BackendTypeBit(mPreferredCanvasBackend) | BackendTypeBit(BackendType::DIRECT2D)));
1827 } else {
1828 mFallbackCanvasBackend =
1829 GetCanvasBackendPref(aPrefsData.mCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
1833 mContentBackendBitmask = aPrefsData.mContentBitmask;
1834 mContentBackend = GetContentBackendPref(mContentBackendBitmask);
1835 if (mContentBackend == BackendType::NONE) {
1836 mContentBackend = aPrefsData.mContentDefault;
1837 // mContentBackendBitmask is our canonical reference for supported
1838 // backends so we need to add the default if we are using it and
1839 // overriding the prefs.
1840 mContentBackendBitmask |= BackendTypeBit(aPrefsData.mContentDefault);
1843 uint32_t swBackendBits = BackendTypeBit(BackendType::SKIA) |
1844 BackendTypeBit(BackendType::CAIRO);
1845 mSoftwareBackend = GetContentBackendPref(swBackendBits);
1847 if (XRE_IsParentProcess()) {
1848 gfxVars::SetContentBackend(mContentBackend);
1849 gfxVars::SetSoftwareBackend(mSoftwareBackend);
1853 /* static */ BackendType
1854 gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
1856 return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
1859 /* static */ BackendType
1860 gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
1862 return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
1865 /* static */ BackendType
1866 gfxPlatform::GetBackendPref(const char* aBackendPrefName, uint32_t &aBackendBitmask)
1868 nsTArray<nsCString> backendList;
1869 nsAutoCString prefString;
1870 if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, prefString))) {
1871 ParseString(prefString, ',', backendList);
1874 uint32_t allowedBackends = 0;
1875 BackendType result = BackendType::NONE;
1876 for (uint32_t i = 0; i < backendList.Length(); ++i) {
1877 BackendType type = BackendTypeForName(backendList[i]);
1878 if (BackendTypeBit(type) & aBackendBitmask) {
1879 allowedBackends |= BackendTypeBit(type);
1880 if (result == BackendType::NONE) {
1881 result = type;
1886 aBackendBitmask = allowedBackends;
1887 return result;
1890 bool
1891 gfxPlatform::InSafeMode()
1893 static bool sSafeModeInitialized = false;
1894 static bool sInSafeMode = false;
1896 if (!sSafeModeInitialized) {
1897 sSafeModeInitialized = true;
1898 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
1899 if (xr) {
1900 xr->GetInSafeMode(&sInSafeMode);
1903 return sInSafeMode;
1906 bool
1907 gfxPlatform::OffMainThreadCompositingEnabled()
1909 return UsesOffMainThreadCompositing();
1912 eCMSMode
1913 gfxPlatform::GetCMSMode()
1915 if (!gCMSInitialized) {
1916 int32_t mode = gfxPrefs::CMSMode();
1917 if (mode >= 0 && mode < eCMSMode_AllCount) {
1918 gCMSMode = static_cast<eCMSMode>(mode);
1921 bool enableV4 = gfxPrefs::CMSEnableV4();
1922 if (enableV4) {
1923 qcms_enable_iccv4();
1925 gCMSInitialized = true;
1927 return gCMSMode;
1931 gfxPlatform::GetRenderingIntent()
1933 // gfxPrefs.h is using 0 as the default for the rendering
1934 // intent preference, based on that being the value for
1935 // QCMS_INTENT_DEFAULT. Assert here to catch if that ever
1936 // changes and we can then figure out what to do about it.
1937 MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
1939 /* Try to query the pref system for a rendering intent. */
1940 int32_t pIntent = gfxPrefs::CMSRenderingIntent();
1941 if ((pIntent < QCMS_INTENT_MIN) || (pIntent > QCMS_INTENT_MAX)) {
1942 /* If the pref is out of range, use embedded profile. */
1943 pIntent = -1;
1945 return pIntent;
1948 void
1949 gfxPlatform::TransformPixel(const Color& in, Color& out, qcms_transform *transform)
1952 if (transform) {
1953 /* we want the bytes in RGB order */
1954 #ifdef IS_LITTLE_ENDIAN
1955 /* ABGR puts the bytes in |RGBA| order on little endian */
1956 uint32_t packed = in.ToABGR();
1957 qcms_transform_data(transform,
1958 (uint8_t *)&packed, (uint8_t *)&packed,
1960 out = Color::FromABGR(packed);
1961 #else
1962 /* ARGB puts the bytes in |ARGB| order on big endian */
1963 uint32_t packed = in.UnusualToARGB();
1964 /* add one to move past the alpha byte */
1965 qcms_transform_data(transform,
1966 (uint8_t *)&packed + 1, (uint8_t *)&packed + 1,
1968 out = Color::UnusualFromARGB(packed);
1969 #endif
1972 else if (&out != &in)
1973 out = in;
1976 void
1977 gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
1979 mem = nullptr;
1980 size = 0;
1983 void
1984 gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size)
1986 nsAutoCString fname;
1987 Preferences::GetCString("gfx.color_management.display_profile", fname);
1988 if (!fname.IsEmpty()) {
1989 qcms_data_from_path(fname.get(), &mem, &size);
1991 else {
1992 gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size);
1996 void
1997 gfxPlatform::CreateCMSOutputProfile()
1999 if (!gCMSOutputProfile) {
2000 /* Determine if we're using the internal override to force sRGB as
2001 an output profile for reftests. See Bug 452125.
2003 Note that we don't normally (outside of tests) set a
2004 default value of this preference, which means nsIPrefBranch::GetBoolPref
2005 will typically throw (and leave its out-param untouched).
2007 if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) {
2008 gCMSOutputProfile = GetCMSsRGBProfile();
2011 if (!gCMSOutputProfile) {
2012 void* mem = nullptr;
2013 size_t size = 0;
2015 GetCMSOutputProfileData(mem, size);
2016 if ((mem != nullptr) && (size > 0)) {
2017 gCMSOutputProfile = qcms_profile_from_memory(mem, size);
2018 free(mem);
2022 /* Determine if the profile looks bogus. If so, close the profile
2023 * and use sRGB instead. See bug 460629, */
2024 if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) {
2025 NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(),
2026 "Builtin sRGB profile tagged as bogus!!!");
2027 qcms_profile_release(gCMSOutputProfile);
2028 gCMSOutputProfile = nullptr;
2031 if (!gCMSOutputProfile) {
2032 gCMSOutputProfile = GetCMSsRGBProfile();
2034 /* Precache the LUT16 Interpolations for the output profile. See
2035 bug 444661 for details. */
2036 qcms_profile_precache_output_transform(gCMSOutputProfile);
2040 qcms_profile *
2041 gfxPlatform::GetCMSOutputProfile()
2043 return gCMSOutputProfile;
2046 qcms_profile *
2047 gfxPlatform::GetCMSsRGBProfile()
2049 if (!gCMSsRGBProfile) {
2051 /* Create the profile using qcms. */
2052 gCMSsRGBProfile = qcms_profile_sRGB();
2054 return gCMSsRGBProfile;
2057 qcms_transform *
2058 gfxPlatform::GetCMSRGBTransform()
2060 if (!gCMSRGBTransform) {
2061 qcms_profile *inProfile, *outProfile;
2062 outProfile = GetCMSOutputProfile();
2063 inProfile = GetCMSsRGBProfile();
2065 if (!inProfile || !outProfile)
2066 return nullptr;
2068 gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
2069 outProfile, QCMS_DATA_RGB_8,
2070 QCMS_INTENT_PERCEPTUAL);
2073 return gCMSRGBTransform;
2076 qcms_transform *
2077 gfxPlatform::GetCMSInverseRGBTransform()
2079 if (!gCMSInverseRGBTransform) {
2080 qcms_profile *inProfile, *outProfile;
2081 inProfile = GetCMSOutputProfile();
2082 outProfile = GetCMSsRGBProfile();
2084 if (!inProfile || !outProfile)
2085 return nullptr;
2087 gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8,
2088 outProfile, QCMS_DATA_RGB_8,
2089 QCMS_INTENT_PERCEPTUAL);
2092 return gCMSInverseRGBTransform;
2095 qcms_transform *
2096 gfxPlatform::GetCMSRGBATransform()
2098 if (!gCMSRGBATransform) {
2099 qcms_profile *inProfile, *outProfile;
2100 outProfile = GetCMSOutputProfile();
2101 inProfile = GetCMSsRGBProfile();
2103 if (!inProfile || !outProfile)
2104 return nullptr;
2106 gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8,
2107 outProfile, QCMS_DATA_RGBA_8,
2108 QCMS_INTENT_PERCEPTUAL);
2111 return gCMSRGBATransform;
2114 /* Shuts down various transforms and profiles for CMS. */
2115 static void ShutdownCMS()
2118 if (gCMSRGBTransform) {
2119 qcms_transform_release(gCMSRGBTransform);
2120 gCMSRGBTransform = nullptr;
2122 if (gCMSInverseRGBTransform) {
2123 qcms_transform_release(gCMSInverseRGBTransform);
2124 gCMSInverseRGBTransform = nullptr;
2126 if (gCMSRGBATransform) {
2127 qcms_transform_release(gCMSRGBATransform);
2128 gCMSRGBATransform = nullptr;
2130 if (gCMSOutputProfile) {
2131 qcms_profile_release(gCMSOutputProfile);
2133 // handle the aliased case
2134 if (gCMSsRGBProfile == gCMSOutputProfile)
2135 gCMSsRGBProfile = nullptr;
2136 gCMSOutputProfile = nullptr;
2138 if (gCMSsRGBProfile) {
2139 qcms_profile_release(gCMSsRGBProfile);
2140 gCMSsRGBProfile = nullptr;
2143 // Reset the state variables
2144 gCMSMode = eCMSMode_Off;
2145 gCMSInitialized = false;
2148 // default SetupClusterBoundaries, based on Unicode properties;
2149 // platform subclasses may override if they wish
2150 void
2151 gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const char16_t *aString)
2153 if (aTextRun->GetFlags() & gfx::ShapedTextFlags::TEXT_IS_8BIT) {
2154 // 8-bit text doesn't have clusters.
2155 // XXX is this true in all languages???
2156 // behdad: don't think so. Czech for example IIRC has a
2157 // 'ch' grapheme.
2158 // jfkthame: but that's not expected to behave as a grapheme cluster
2159 // for selection/editing/etc.
2160 return;
2163 aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength());
2166 int32_t
2167 gfxPlatform::GetBidiNumeralOption()
2169 if (mBidiNumeralOption == UNINITIALIZED_VALUE) {
2170 mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0);
2172 return mBidiNumeralOption;
2175 /* static */ void
2176 gfxPlatform::FlushFontAndWordCaches()
2178 gfxFontCache *fontCache = gfxFontCache::GetCache();
2179 if (fontCache) {
2180 fontCache->AgeAllGenerations();
2181 fontCache->FlushShapedWordCaches();
2184 gfxPlatform::PurgeSkiaFontCache();
2187 /* static */ void
2188 gfxPlatform::ForceGlobalReflow()
2190 MOZ_ASSERT(NS_IsMainThread());
2191 if (XRE_IsParentProcess()) {
2192 // Modify a preference that will trigger reflow everywhere (in all
2193 // content processes, as well as the parent).
2194 static const char kPrefName[] = "font.internaluseonly.changed";
2195 bool fontInternalChange = Preferences::GetBool(kPrefName, false);
2196 Preferences::SetBool(kPrefName, !fontInternalChange);
2197 } else {
2198 // Send a notification that will be observed by PresShells in this
2199 // process only.
2200 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
2201 if (obs) {
2202 obs->NotifyObservers(nullptr, "font-info-updated", nullptr);
2207 void
2208 gfxPlatform::FontsPrefsChanged(const char *aPref)
2210 NS_ASSERTION(aPref != nullptr, "null preference");
2211 if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
2212 mAllowDownloadableFonts = UNINITIALIZED_VALUE;
2213 } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
2214 mFallbackUsesCmaps = UNINITIALIZED_VALUE;
2215 } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) {
2216 mWordCacheCharLimit = UNINITIALIZED_VALUE;
2217 FlushFontAndWordCaches();
2218 } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) {
2219 mWordCacheMaxEntries = UNINITIALIZED_VALUE;
2220 FlushFontAndWordCaches();
2221 } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
2222 mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
2223 FlushFontAndWordCaches();
2224 } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) {
2225 mBidiNumeralOption = UNINITIALIZED_VALUE;
2226 } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
2227 mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
2228 gfxFontCache::GetCache()->AgeAllGenerations();
2229 gfxFontCache::GetCache()->NotifyGlyphsChanged();
2234 mozilla::LogModule*
2235 gfxPlatform::GetLog(eGfxLog aWhichLog)
2237 // logs shared across gfx
2238 static LazyLogModule sFontlistLog("fontlist");
2239 static LazyLogModule sFontInitLog("fontinit");
2240 static LazyLogModule sTextrunLog("textrun");
2241 static LazyLogModule sTextrunuiLog("textrunui");
2242 static LazyLogModule sCmapDataLog("cmapdata");
2243 static LazyLogModule sTextPerfLog("textperf");
2245 switch (aWhichLog) {
2246 case eGfxLog_fontlist:
2247 return sFontlistLog;
2248 case eGfxLog_fontinit:
2249 return sFontInitLog;
2250 case eGfxLog_textrun:
2251 return sTextrunLog;
2252 case eGfxLog_textrunui:
2253 return sTextrunuiLog;
2254 case eGfxLog_cmapdata:
2255 return sCmapDataLog;
2256 case eGfxLog_textperf:
2257 return sTextPerfLog;
2260 MOZ_ASSERT_UNREACHABLE("Unexpected log type");
2261 return nullptr;
2264 RefPtr<mozilla::gfx::DrawTarget>
2265 gfxPlatform::ScreenReferenceDrawTarget()
2267 return (mScreenReferenceDrawTarget)
2268 ? mScreenReferenceDrawTarget
2269 : gPlatform->CreateOffscreenContentDrawTarget(
2270 IntSize(1, 1), SurfaceFormat::B8G8R8A8, true);
2273 mozilla::gfx::SurfaceFormat
2274 gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent)
2276 switch (aContent) {
2277 case gfxContentType::COLOR:
2278 switch (GetOffscreenFormat()) {
2279 case SurfaceFormat::A8R8G8B8_UINT32:
2280 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2281 case SurfaceFormat::X8R8G8B8_UINT32:
2282 return mozilla::gfx::SurfaceFormat::B8G8R8X8;
2283 case SurfaceFormat::R5G6B5_UINT16:
2284 return mozilla::gfx::SurfaceFormat::R5G6B5_UINT16;
2285 default:
2286 NS_NOTREACHED("unknown gfxImageFormat for gfxContentType::COLOR");
2287 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2289 case gfxContentType::ALPHA:
2290 return mozilla::gfx::SurfaceFormat::A8;
2291 case gfxContentType::COLOR_ALPHA:
2292 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2293 default:
2294 NS_NOTREACHED("unknown gfxContentType");
2295 return mozilla::gfx::SurfaceFormat::B8G8R8A8;
2299 gfxImageFormat
2300 gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
2302 switch (aContent) {
2303 case gfxContentType::COLOR:
2304 return GetOffscreenFormat();
2305 case gfxContentType::ALPHA:
2306 return SurfaceFormat::A8;
2307 case gfxContentType::COLOR_ALPHA:
2308 return SurfaceFormat::A8R8G8B8_UINT32;
2309 default:
2310 NS_NOTREACHED("unknown gfxContentType");
2311 return SurfaceFormat::A8R8G8B8_UINT32;
2316 * There are a number of layers acceleration (or layers in general) preferences
2317 * that should be consistent for the lifetime of the application (bug 840967).
2318 * As such, we will evaluate them all as soon as one of them is evaluated
2319 * and remember the values. Changing these preferences during the run will
2320 * not have any effect until we restart.
2322 static mozilla::Atomic<bool> sLayersSupportsHardwareVideoDecoding(false);
2323 static bool sLayersHardwareVideoDecodingFailed = false;
2324 static bool sBufferRotationCheckPref = true;
2326 static mozilla::Atomic<bool> sLayersAccelerationPrefsInitialized(false);
2328 void VideoDecodingFailedChangedCallback(const char* aPref, void*)
2330 sLayersHardwareVideoDecodingFailed = Preferences::GetBool(aPref, false);
2331 gfxPlatform::GetPlatform()->UpdateCanUseHardwareVideoDecoding();
2334 void
2335 gfxPlatform::UpdateCanUseHardwareVideoDecoding()
2337 if (XRE_IsParentProcess()) {
2338 gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding());
2342 void
2343 gfxPlatform::InitAcceleration()
2345 if (sLayersAccelerationPrefsInitialized) {
2346 return;
2349 InitCompositorAccelerationPrefs();
2351 // If this is called for the first time on a non-main thread, we're screwed.
2352 // At the moment there's no explicit guarantee that the main thread calls
2353 // this before the compositor thread, but let's at least make the assumption
2354 // explicit.
2355 MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
2357 gfxPrefs::GetSingleton();
2359 nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
2360 nsCString discardFailureId;
2361 int32_t status;
2363 if (XRE_IsParentProcess()) {
2364 gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
2365 gfxVars::SetOffscreenFormat(GetOffscreenFormat());
2366 gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL(
2367 RequiresAcceleratedGLContextForCompositorOGL());
2368 #ifdef XP_WIN
2369 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX,
2370 discardFailureId, &status))) {
2371 gfxVars::SetAllowD3D11KeyedMutex(status == nsIGfxInfo::FEATURE_STATUS_OK);
2372 } else {
2373 // If we couldn't properly evaluate the status, err on the side
2374 // of caution and give this functionality to the user.
2375 gfxCriticalNote << "Cannot evaluate keyed mutex feature status";
2376 gfxVars::SetAllowD3D11KeyedMutex(true);
2378 #endif
2381 if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) &&
2382 #ifdef XP_WIN
2383 Preferences::GetBool("media.wmf.dxva.enabled", true) &&
2384 #endif
2385 NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING,
2386 discardFailureId, &status))) {
2387 if (status == nsIGfxInfo::FEATURE_STATUS_OK || gfxPrefs::HardwareVideoDecodingForceEnabled()) {
2388 sLayersSupportsHardwareVideoDecoding = true;
2392 sLayersAccelerationPrefsInitialized = true;
2394 if (XRE_IsParentProcess()) {
2395 Preferences::RegisterCallbackAndCall(VideoDecodingFailedChangedCallback,
2396 "media.hardware-video-decoding.failed");
2397 InitGPUProcessPrefs();
2401 void
2402 gfxPlatform::InitGPUProcessPrefs()
2404 // We want to hide this from about:support, so only set a default if the
2405 // pref is known to be true.
2406 if (!gfxPrefs::GPUProcessEnabled() && !gfxPrefs::GPUProcessForceEnabled()) {
2407 return;
2410 FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
2412 // We require E10S - otherwise, there is very little benefit to the GPU
2413 // process, since the UI process must still use acceleration for
2414 // performance.
2415 if (!BrowserTabsRemoteAutostart()) {
2416 gpuProc.DisableByDefault(
2417 FeatureStatus::Unavailable,
2418 "Multi-process mode is not enabled",
2419 NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_E10S"));
2420 } else {
2421 gpuProc.SetDefaultFromPref(
2422 gfxPrefs::GetGPUProcessEnabledPrefName(),
2423 true,
2424 gfxPrefs::GetGPUProcessEnabledPrefDefault());
2427 if (gfxPrefs::GPUProcessForceEnabled()) {
2428 gpuProc.UserForceEnable("User force-enabled via pref");
2431 if (IsHeadless()) {
2432 gpuProc.ForceDisable(
2433 FeatureStatus::Blocked,
2434 "Headless mode is enabled",
2435 NS_LITERAL_CSTRING("FEATURE_FAILURE_HEADLESS_MODE"));
2436 return;
2438 if (InSafeMode()) {
2439 gpuProc.ForceDisable(
2440 FeatureStatus::Blocked,
2441 "Safe-mode is enabled",
2442 NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
2443 return;
2445 if (gfxPrefs::LayerScopeEnabled()) {
2446 gpuProc.ForceDisable(
2447 FeatureStatus::Blocked,
2448 "LayerScope does not work in the GPU process",
2449 NS_LITERAL_CSTRING("FEATURE_FAILURE_LAYERSCOPE"));
2450 return;
2454 void
2455 gfxPlatform::InitCompositorAccelerationPrefs()
2457 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
2459 FeatureState& feature = gfxConfig::GetFeature(Feature::HW_COMPOSITING);
2461 // Base value - does the platform allow acceleration?
2462 if (feature.SetDefault(AccelerateLayersByDefault(),
2463 FeatureStatus::Blocked,
2464 "Acceleration blocked by platform"))
2466 if (gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly()) {
2467 feature.UserDisable("Disabled by pref",
2468 NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF"));
2469 } else if (acceleratedEnv && *acceleratedEnv == '0') {
2470 feature.UserDisable("Disabled by envvar",
2471 NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_ENV"));
2473 } else {
2474 if (acceleratedEnv && *acceleratedEnv == '1') {
2475 feature.UserEnable("Enabled by envvar");
2479 // This has specific meaning elsewhere, so we always record it.
2480 if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
2481 feature.UserForceEnable("Force-enabled by pref");
2484 // Safe and headless modes override everything.
2485 if (InSafeMode()) {
2486 feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by safe-mode",
2487 NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
2489 if (IsHeadless()) {
2490 feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by headless mode",
2491 NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_HEADLESSMODE"));
2495 /*static*/ bool
2496 gfxPlatform::WebRenderPrefEnabled()
2498 return gfxPrefs::WebRenderAll() || gfxPrefs::WebRenderEnabledDoNotUseDirectly();
2501 /*static*/ bool
2502 gfxPlatform::WebRenderEnvvarEnabled()
2504 const char* env = PR_GetEnv("MOZ_WEBRENDER");
2505 return (env && *env == '1');
2508 void
2509 gfxPlatform::InitWebRenderConfig()
2511 bool prefEnabled = WebRenderPrefEnabled();
2513 ScopedGfxFeatureReporter reporter("WR", prefEnabled);
2514 if (!XRE_IsParentProcess()) {
2515 // The parent process runs through all the real decision-making code
2516 // later in this function. For other processes we still want to report
2517 // the state of the feature for crash reports.
2518 if (gfxVars::UseWebRender()) {
2519 reporter.SetSuccessful();
2521 return;
2524 FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER);
2526 featureWebRender.DisableByDefault(
2527 FeatureStatus::OptIn,
2528 "WebRender is an opt-in feature",
2529 NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
2531 if (prefEnabled) {
2532 featureWebRender.UserEnable("Enabled by pref");
2533 } else if (WebRenderEnvvarEnabled()) {
2534 featureWebRender.UserEnable("Enabled by envvar");
2537 // HW_COMPOSITING being disabled implies interfacing with the GPU might break
2538 if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
2539 featureWebRender.ForceDisable(
2540 FeatureStatus::Unavailable,
2541 "Hardware compositing is disabled",
2542 NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_NEED_HWCOMP"));
2545 // WebRender relies on the GPU process when on Windows
2546 #ifdef XP_WIN
2547 if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
2548 featureWebRender.ForceDisable(
2549 FeatureStatus::Unavailable,
2550 "GPU Process is disabled",
2551 NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED"));
2553 #endif
2555 if (InSafeMode()) {
2556 featureWebRender.ForceDisable(
2557 FeatureStatus::Unavailable,
2558 "Safe-mode is enabled",
2559 NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
2562 #ifndef MOZ_BUILD_WEBRENDER
2563 featureWebRender.ForceDisable(
2564 FeatureStatus::Unavailable,
2565 "Build doesn't include WebRender",
2566 NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_WEBRENDER"));
2567 #endif
2569 #ifdef XP_WIN
2570 if (Preferences::GetBool("gfx.webrender.force-angle", false)) {
2571 if (!gfxConfig::IsEnabled(Feature::D3D11_HW_ANGLE)) {
2572 featureWebRender.ForceDisable(
2573 FeatureStatus::Unavailable,
2574 "ANGLE is disabled",
2575 NS_LITERAL_CSTRING("FEATURE_FAILURE_ANGLE_DISABLED"));
2576 } else {
2577 gfxVars::SetUseWebRenderANGLE(gfxConfig::IsEnabled(Feature::WEBRENDER));
2580 #endif
2582 if (Preferences::GetBool("gfx.webrender.program-binary", false)) {
2583 gfx::gfxVars::SetUseWebRenderProgramBinary(gfxConfig::IsEnabled(Feature::WEBRENDER));
2586 #ifdef MOZ_WIDGET_ANDROID
2587 featureWebRender.ForceDisable(
2588 FeatureStatus::Unavailable,
2589 "WebRender not ready for use on Android",
2590 NS_LITERAL_CSTRING("FEATURE_FAILURE_ANDROID"));
2591 #endif
2593 // gfxFeature is not usable in the GPU process, so we use gfxVars to transmit this feature
2594 if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
2595 gfxVars::SetUseWebRender(true);
2596 reporter.SetSuccessful();
2598 if (XRE_IsParentProcess()) {
2599 Preferences::RegisterPrefixCallbackAndCall(WebRenderDebugPrefChangeCallback,
2600 WR_DEBUG_PREF);
2604 #ifdef XP_WIN
2605 if (Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false)) {
2606 // XXX relax win version to windows 8.
2607 if (IsWin10OrLater() &&
2608 gfxVars::UseWebRender() &&
2609 gfxVars::UseWebRenderANGLE()) {
2610 gfxVars::SetUseWebRenderDCompWin(true);
2613 #endif
2616 void
2617 gfxPlatform::InitOMTPConfig()
2619 ScopedGfxFeatureReporter reporter("OMTP");
2621 FeatureState& omtp = gfxConfig::GetFeature(Feature::OMTP);
2622 int32_t paintWorkerCount = PaintThread::CalculatePaintWorkerCount();
2624 if (!XRE_IsParentProcess()) {
2625 // The parent process runs through all the real decision-making code
2626 // later in this function. For other processes we still want to report
2627 // the state of the feature for crash reports.
2628 if (gfxVars::UseOMTP()) {
2629 reporter.SetSuccessful(paintWorkerCount);
2631 return;
2634 omtp.SetDefaultFromPref(
2635 "layers.omtp.enabled",
2636 true,
2637 Preferences::GetBool("layers.omtp.enabled", false, PrefValueKind::Default));
2639 if (mContentBackend == BackendType::CAIRO) {
2640 omtp.ForceDisable(FeatureStatus::Broken, "OMTP is not supported when using cairo",
2641 NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF"));
2644 if (InSafeMode()) {
2645 omtp.ForceDisable(FeatureStatus::Blocked, "OMTP blocked by safe-mode",
2646 NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE"));
2647 } else if (gfxPlatform::UsesTiling() && gfxPrefs::TileEdgePaddingEnabled()) {
2648 omtp.ForceDisable(FeatureStatus::Blocked, "OMTP does not yet support tiling with edge padding",
2649 NS_LITERAL_CSTRING("FEATURE_FAILURE_OMTP_TILING"));
2652 if (omtp.IsEnabled()) {
2653 gfxVars::SetUseOMTP(true);
2654 reporter.SetSuccessful(paintWorkerCount);
2658 bool
2659 gfxPlatform::CanUseHardwareVideoDecoding()
2661 // this function is called from the compositor thread, so it is not
2662 // safe to init the prefs etc. from here.
2663 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2664 return sLayersSupportsHardwareVideoDecoding && !sLayersHardwareVideoDecodingFailed;
2667 bool
2668 gfxPlatform::AccelerateLayersByDefault()
2670 #if defined(MOZ_GL_PROVIDER) || defined(MOZ_WIDGET_UIKIT)
2671 return true;
2672 #else
2673 return false;
2674 #endif
2677 bool
2678 gfxPlatform::BufferRotationEnabled()
2680 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2682 return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled();
2685 void
2686 gfxPlatform::DisableBufferRotation()
2688 MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
2690 sBufferRotationCheckPref = false;
2693 /* static */ bool
2694 gfxPlatform::UsesOffMainThreadCompositing()
2696 if (XRE_GetProcessType() == GeckoProcessType_GPU) {
2697 return true;
2700 static bool firstTime = true;
2701 static bool result = false;
2703 if (firstTime) {
2704 MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
2705 result =
2706 gfxVars::BrowserTabsRemoteAutostart() ||
2707 !gfxPrefs::LayersOffMainThreadCompositionForceDisabled();
2708 #if defined(MOZ_WIDGET_GTK)
2709 // Linux users who chose OpenGL are being grandfathered in to OMTC
2710 result |= gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly();
2712 #endif
2713 firstTime = false;
2716 return result;
2719 bool
2720 gfxPlatform::UsesTiling() const
2722 return gfxPrefs::LayersTilesEnabled();
2725 /***
2726 * The preference "layout.frame_rate" has 3 meanings depending on the value:
2728 * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw vsync fails.
2729 * 0 = ASAP mode - used during talos testing.
2730 * X = Software vsync at a rate of X times per second.
2732 already_AddRefed<mozilla::gfx::VsyncSource>
2733 gfxPlatform::CreateHardwareVsyncSource()
2735 RefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource();
2736 return softwareVsync.forget();
2739 /* static */ bool
2740 gfxPlatform::IsInLayoutAsapMode()
2742 // There are 2 modes of ASAP mode.
2743 // 1 is that the refresh driver and compositor are in lock step
2744 // the second is that the compositor goes ASAP and the refresh driver
2745 // goes at whatever the configurated rate is. This only checks the version
2746 // talos uses, which is the refresh driver and compositor are in lockstep.
2747 return gfxPrefs::LayoutFrameRate() == 0;
2750 /* static */ bool
2751 gfxPlatform::ForceSoftwareVsync()
2753 return gfxPrefs::LayoutFrameRate() > 0;
2756 /* static */ int
2757 gfxPlatform::GetSoftwareVsyncRate()
2759 int preferenceRate = gfxPrefs::LayoutFrameRate();
2760 if (preferenceRate <= 0) {
2761 return gfxPlatform::GetDefaultFrameRate();
2763 return preferenceRate;
2766 /* static */ int
2767 gfxPlatform::GetDefaultFrameRate()
2769 return 60;
2772 void
2773 gfxPlatform::GetAzureBackendInfo(mozilla::widget::InfoObject& aObj)
2775 if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
2776 aObj.DefineProperty("AzureCanvasBackend (UI Process)", GetBackendName(mPreferredCanvasBackend));
2777 aObj.DefineProperty("AzureFallbackCanvasBackend (UI Process)", GetBackendName(mFallbackCanvasBackend));
2778 aObj.DefineProperty("AzureContentBackend (UI Process)", GetBackendName(mContentBackend));
2780 // Assume content process' backend prefs.
2781 BackendPrefsData data = GetBackendPrefs();
2782 BackendType canvasBackend = GetCanvasBackendPref(data.mCanvasBitmask);
2783 if (canvasBackend == BackendType::NONE) {
2784 canvasBackend = data.mCanvasDefault;
2786 BackendType contentBackend = GetContentBackendPref(data.mContentBitmask);
2787 if (contentBackend == BackendType::NONE) {
2788 contentBackend = data.mContentDefault;
2790 aObj.DefineProperty("AzureCanvasBackend", GetBackendName(canvasBackend));
2791 aObj.DefineProperty("AzureContentBackend", GetBackendName(contentBackend));
2792 } else {
2793 aObj.DefineProperty("AzureCanvasBackend", GetBackendName(mPreferredCanvasBackend));
2794 aObj.DefineProperty("AzureFallbackCanvasBackend", GetBackendName(mFallbackCanvasBackend));
2795 aObj.DefineProperty("AzureContentBackend", GetBackendName(mContentBackend));
2798 aObj.DefineProperty("AzureCanvasAccelerated", AllowOpenGLCanvas());
2801 void
2802 gfxPlatform::GetApzSupportInfo(mozilla::widget::InfoObject& aObj)
2804 if (!gfxPlatform::AsyncPanZoomEnabled()) {
2805 return;
2808 if (SupportsApzWheelInput()) {
2809 aObj.DefineProperty("ApzWheelInput", 1);
2812 if (SupportsApzTouchInput()) {
2813 aObj.DefineProperty("ApzTouchInput", 1);
2816 if (SupportsApzDragInput()) {
2817 aObj.DefineProperty("ApzDragInput", 1);
2820 if (SupportsApzKeyboardInput() && !gfxPrefs::AccessibilityBrowseWithCaret()) {
2821 aObj.DefineProperty("ApzKeyboardInput", 1);
2824 if (SupportsApzAutoscrolling()) {
2825 aObj.DefineProperty("ApzAutoscrollInput", 1);
2829 void
2830 gfxPlatform::GetTilesSupportInfo(mozilla::widget::InfoObject& aObj)
2832 if (!gfxPrefs::LayersTilesEnabled()) {
2833 return;
2836 IntSize tileSize = gfxVars::TileSize();
2837 aObj.DefineProperty("TileHeight", tileSize.height);
2838 aObj.DefineProperty("TileWidth", tileSize.width);
2841 /*static*/ bool
2842 gfxPlatform::AsyncPanZoomEnabled()
2844 #if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
2845 // For XUL applications (everything but Firefox on Android)
2846 // we only want to use APZ when E10S is enabled. If
2847 // we ever get input events off the main thread we can consider relaxing
2848 // this requirement.
2849 if (!BrowserTabsRemoteAutostart()) {
2850 return false;
2852 #endif
2853 #ifdef MOZ_WIDGET_ANDROID
2854 return true;
2855 #else
2856 if (!gfxPrefs::SingletonExists()) {
2857 // Make sure the gfxPrefs has been initialized before reading from it.
2858 MOZ_ASSERT(NS_IsMainThread());
2859 gfxPrefs::GetSingleton();
2861 return gfxPrefs::AsyncPanZoomEnabledDoNotUseDirectly();
2862 #endif
2865 /*static*/ bool
2866 gfxPlatform::PerfWarnings()
2868 return gfxPrefs::PerfWarnings();
2871 void
2872 gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends)
2874 if (gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING)) {
2875 aBackends.AppendElement(LayersBackend::LAYERS_OPENGL);
2877 else {
2878 static int tell_me_once = 0;
2879 if (!tell_me_once) {
2880 NS_WARNING("OpenGL-accelerated layers are not supported on this system");
2881 tell_me_once = 1;
2883 #ifdef MOZ_WIDGET_ANDROID
2884 MOZ_CRASH("OpenGL-accelerated layers are a hard requirement on this platform. "
2885 "Cannot continue without support for them");
2886 #endif
2890 void
2891 gfxPlatform::GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layers::LayersBackend>& aBackends)
2893 if (useAcceleration) {
2894 GetAcceleratedCompositorBackends(aBackends);
2896 aBackends.AppendElement(LayersBackend::LAYERS_BASIC);
2899 void
2900 gfxPlatform::NotifyCompositorCreated(LayersBackend aBackend)
2902 if (mCompositorBackend == aBackend) {
2903 return;
2906 if (mCompositorBackend != LayersBackend::LAYERS_NONE) {
2907 gfxCriticalNote << "Compositors might be mixed ("
2908 << int(mCompositorBackend) << "," << int(aBackend) << ")";
2911 // Set the backend before we notify so it's available immediately.
2912 mCompositorBackend = aBackend;
2914 // Notify that we created a compositor, so telemetry can update.
2915 NS_DispatchToMainThread(
2916 NS_NewRunnableFunction("gfxPlatform::NotifyCompositorCreated", [] {
2917 if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
2918 obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
2920 }));
2923 /* static */ void
2924 gfxPlatform::NotifyGPUProcessDisabled()
2926 if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
2927 gfxConfig::GetFeature(Feature::WEBRENDER).ForceDisable(
2928 FeatureStatus::Unavailable,
2929 "GPU Process is disabled",
2930 NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED"));
2931 gfxVars::SetUseWebRender(false);
2935 void
2936 gfxPlatform::FetchAndImportContentDeviceData()
2938 MOZ_ASSERT(XRE_IsContentProcess());
2940 if (gContentDeviceInitData) {
2941 ImportContentDeviceData(*gContentDeviceInitData);
2942 return;
2945 mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
2947 mozilla::gfx::ContentDeviceData data;
2948 cc->SendGetGraphicsDeviceInitData(&data);
2950 ImportContentDeviceData(data);
2953 void
2954 gfxPlatform::ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData)
2956 MOZ_ASSERT(XRE_IsContentProcess());
2958 const DevicePrefs& prefs = aData.prefs();
2959 gfxConfig::Inherit(Feature::HW_COMPOSITING, prefs.hwCompositing());
2960 gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, prefs.oglCompositing());
2963 void
2964 gfxPlatform::BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut)
2966 MOZ_ASSERT(XRE_IsParentProcess());
2968 // Make sure our settings are synchronized from the GPU process.
2969 GPUProcessManager::Get()->EnsureGPUReady();
2971 aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
2972 aOut->prefs().oglCompositing() = gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
2975 void
2976 gfxPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData)
2978 MOZ_ASSERT(XRE_IsParentProcess());
2980 gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
2981 gfxConfig::ImportChange(Feature::ADVANCED_LAYERS, aData.advancedLayers());
2984 bool
2985 gfxPlatform::SupportsApzTouchInput() const
2987 return dom::TouchEvent::PrefEnabled(nullptr);
2990 bool
2991 gfxPlatform::SupportsApzDragInput() const
2993 return gfxPrefs::APZDragEnabled();
2996 bool
2997 gfxPlatform::SupportsApzKeyboardInput() const
2999 return gfxPrefs::APZKeyboardEnabled();
3002 bool
3003 gfxPlatform::SupportsApzAutoscrolling() const
3005 return gfxPrefs::APZAutoscrollEnabled();
3008 void
3009 gfxPlatform::InitOpenGLConfig()
3011 #ifdef XP_WIN
3012 // Don't enable by default on Windows, since it could show up in about:support even
3013 // though it'll never get used. Only attempt if user enables the pref
3014 if (!Preferences::GetBool("layers.prefer-opengl")){
3015 return;
3017 #endif
3019 FeatureState& openGLFeature = gfxConfig::GetFeature(Feature::OPENGL_COMPOSITING);
3021 // Check to see hw comp supported
3022 if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
3023 openGLFeature.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled",
3024 NS_LITERAL_CSTRING("FEATURE_FAILURE_OPENGL_NEED_HWCOMP"));
3025 return;
3028 #ifdef XP_WIN
3029 openGLFeature.SetDefaultFromPref(
3030 gfxPrefs::GetLayersPreferOpenGLPrefName(),
3031 true,
3032 gfxPrefs::GetLayersPreferOpenGLPrefDefault());
3033 #else
3034 openGLFeature.EnableByDefault();
3035 #endif
3037 // When layers acceleration is force-enabled, enable it even for blacklisted
3038 // devices.
3039 if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
3040 openGLFeature.UserForceEnable("Force-enabled by pref");
3041 return;
3044 nsCString message;
3045 nsCString failureId;
3046 if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &message, failureId)) {
3047 openGLFeature.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
3051 bool
3052 gfxPlatform::IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage, nsCString& aFailureId)
3054 nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
3055 if (!gfxInfo) {
3056 return true;
3059 int32_t status;
3060 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) &&
3061 status != nsIGfxInfo::FEATURE_STATUS_OK)
3063 aOutMessage->AssignLiteral("#BLOCKLIST_");
3064 aOutMessage->AppendASCII(aFailureId.get());
3065 return false;
3068 return true;