/src/mozilla-central/gfx/thebes/gfxPlatform.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
2 | | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #include "mozilla/FontPropertyTypes.h" |
7 | | #include "mozilla/layers/CompositorManagerChild.h" |
8 | | #include "mozilla/layers/CompositorThread.h" |
9 | | #include "mozilla/layers/ImageBridgeChild.h" |
10 | | #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter |
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" |
22 | | |
23 | | #include "mozilla/Logging.h" |
24 | | #include "mozilla/Services.h" |
25 | | #include "nsAppDirectoryServiceDefs.h" |
26 | | |
27 | | #include "gfxCrashReporterUtils.h" |
28 | | #include "gfxPlatform.h" |
29 | | #include "gfxPrefs.h" |
30 | | #include "gfxEnv.h" |
31 | | #include "gfxTextRun.h" |
32 | | #include "gfxUserFontSet.h" |
33 | | #include "gfxConfig.h" |
34 | | #include "VRProcessManager.h" |
35 | | #include "VRThread.h" |
36 | | |
37 | | #ifdef XP_WIN |
38 | | #include <process.h> |
39 | | #define getpid _getpid |
40 | | #else |
41 | | #include <unistd.h> |
42 | | #endif |
43 | | |
44 | | #include "nsXULAppAPI.h" |
45 | | #include "nsDirectoryServiceUtils.h" |
46 | | #include "nsDirectoryServiceDefs.h" |
47 | | |
48 | | #if defined(XP_WIN) |
49 | | #include "gfxWindowsPlatform.h" |
50 | | #elif defined(XP_MACOSX) |
51 | | #include "gfxPlatformMac.h" |
52 | | #include "gfxQuartzSurface.h" |
53 | | #include "nsCocoaFeatures.h" |
54 | | #elif defined(MOZ_WIDGET_GTK) |
55 | | #include "gfxPlatformGtk.h" |
56 | | #elif defined(ANDROID) |
57 | | #include "gfxAndroidPlatform.h" |
58 | | #endif |
59 | | |
60 | | #ifdef XP_WIN |
61 | | #include <windows.h> |
62 | | #include "mozilla/WindowsVersion.h" |
63 | | #include "mozilla/gfx/DeviceManagerDx.h" |
64 | | #endif |
65 | | |
66 | | #include "nsGkAtoms.h" |
67 | | #include "gfxPlatformFontList.h" |
68 | | #include "gfxContext.h" |
69 | | #include "gfxImageSurface.h" |
70 | | #include "nsUnicodeProperties.h" |
71 | | #include "harfbuzz/hb.h" |
72 | | #include "gfxGraphiteShaper.h" |
73 | | #include "gfx2DGlue.h" |
74 | | #include "gfxGradientCache.h" |
75 | | #include "gfxUtils.h" // for NextPowerOfTwo |
76 | | #include "gfxFontMissingGlyphs.h" |
77 | | |
78 | | #include "nsExceptionHandler.h" |
79 | | #include "nsUnicodeRange.h" |
80 | | #include "nsServiceManagerUtils.h" |
81 | | #include "nsTArray.h" |
82 | | #include "nsIObserverService.h" |
83 | | #include "nsIScreenManager.h" |
84 | | #include "FrameMetrics.h" |
85 | | #include "MainThreadUtils.h" |
86 | | |
87 | | #include "nsWeakReference.h" |
88 | | |
89 | | #include "cairo.h" |
90 | | #include "qcms.h" |
91 | | |
92 | | #include "imgITools.h" |
93 | | |
94 | | #include "plstr.h" |
95 | | #include "nsCRT.h" |
96 | | #include "GLContext.h" |
97 | | #include "GLContextProvider.h" |
98 | | #include "mozilla/gfx/Logging.h" |
99 | | |
100 | | #ifdef USE_SKIA |
101 | | # ifdef __GNUC__ |
102 | | # pragma GCC diagnostic push |
103 | | # pragma GCC diagnostic ignored "-Wshadow" |
104 | | # endif |
105 | | # include "skia/include/core/SkGraphics.h" |
106 | | # ifdef USE_SKIA_GPU |
107 | | # include "skia/include/gpu/GrContext.h" |
108 | | # include "skia/include/gpu/gl/GrGLInterface.h" |
109 | | # include "SkiaGLGlue.h" |
110 | | # endif |
111 | | # ifdef MOZ_ENABLE_FREETYPE |
112 | | # include "skia/include/ports/SkTypeface_cairo.h" |
113 | | # endif |
114 | | # include "mozilla/gfx/SkMemoryReporter.h" |
115 | | # ifdef __GNUC__ |
116 | | # pragma GCC diagnostic pop // -Wshadow |
117 | | # endif |
118 | | static const uint32_t kDefaultGlyphCacheSize = -1; |
119 | | |
120 | | #endif |
121 | | |
122 | | #if !defined(USE_SKIA) || !defined(USE_SKIA_GPU) |
123 | | class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted { |
124 | | }; |
125 | | #endif |
126 | | |
127 | | #include "mozilla/Preferences.h" |
128 | | #include "mozilla/Assertions.h" |
129 | | #include "mozilla/Atomics.h" |
130 | | #include "mozilla/Attributes.h" |
131 | | #include "mozilla/Mutex.h" |
132 | | |
133 | | #include "nsAlgorithm.h" |
134 | | #include "nsIGfxInfo.h" |
135 | | #include "nsIXULRuntime.h" |
136 | | #include "VsyncSource.h" |
137 | | #include "SoftwareVsyncSource.h" |
138 | | #include "nscore.h" // for NS_FREE_PERMANENT_DATA |
139 | | #include "mozilla/dom/ContentChild.h" |
140 | | #include "mozilla/dom/TouchEvent.h" |
141 | | #include "gfxVR.h" |
142 | | #include "VRManagerChild.h" |
143 | | #include "mozilla/gfx/GPUParent.h" |
144 | | #include "mozilla/layers/MemoryReportingMLGPU.h" |
145 | | #include "prsystem.h" |
146 | | |
147 | | namespace mozilla { |
148 | | namespace layers { |
149 | | void ShutdownTileCache(); |
150 | | } // namespace layers |
151 | | } // namespace mozilla |
152 | | |
153 | | using namespace mozilla; |
154 | | using namespace mozilla::layers; |
155 | | using namespace mozilla::gl; |
156 | | using namespace mozilla::gfx; |
157 | | |
158 | | gfxPlatform *gPlatform = nullptr; |
159 | | static bool gEverInitialized = false; |
160 | | |
161 | | const ContentDeviceData* gContentDeviceInitData = nullptr; |
162 | | |
163 | | static Mutex* gGfxPlatformPrefsLock = nullptr; |
164 | | |
165 | | // These two may point to the same profile |
166 | | static qcms_profile *gCMSOutputProfile = nullptr; |
167 | | static qcms_profile *gCMSsRGBProfile = nullptr; |
168 | | |
169 | | static bool gCMSRGBTransformFailed = false; |
170 | | static qcms_transform *gCMSRGBTransform = nullptr; |
171 | | static qcms_transform *gCMSInverseRGBTransform = nullptr; |
172 | | static qcms_transform *gCMSRGBATransform = nullptr; |
173 | | |
174 | | static bool gCMSInitialized = false; |
175 | | static eCMSMode gCMSMode = eCMSMode_Off; |
176 | | |
177 | | static void ShutdownCMS(); |
178 | | |
179 | | #include "mozilla/gfx/2D.h" |
180 | | #include "mozilla/gfx/SourceSurfaceCairo.h" |
181 | | using namespace mozilla::gfx; |
182 | | |
183 | | /* Class to listen for pref changes so that chrome code can dynamically |
184 | | force sRGB as an output profile. See Bug #452125. */ |
185 | | class SRGBOverrideObserver final : public nsIObserver, |
186 | | public nsSupportsWeakReference |
187 | | { |
188 | 0 | ~SRGBOverrideObserver() = default; |
189 | | public: |
190 | | NS_DECL_ISUPPORTS |
191 | | NS_DECL_NSIOBSERVER |
192 | | }; |
193 | | |
194 | | /// This override of the LogForwarder, initially used for the critical graphics |
195 | | /// errors, is sending the log to the crash annotations as well, but only |
196 | | /// if the capacity set with the method below is >= 2. We always retain the |
197 | | /// very first critical message, and the latest capacity-1 messages are |
198 | | /// rotated through. Note that we don't expect the total number of times |
199 | | /// this gets called to be large - it is meant for critical errors only. |
200 | | |
201 | | class CrashStatsLogForwarder: public mozilla::gfx::LogForwarder |
202 | | { |
203 | | public: |
204 | | explicit CrashStatsLogForwarder(CrashReporter::Annotation aKey); |
205 | | void Log(const std::string& aString) override; |
206 | | void CrashAction(LogReason aReason) override; |
207 | | bool UpdateStringsVector(const std::string& aString) override; |
208 | | |
209 | | LoggingRecord LoggingRecordCopy() override; |
210 | | |
211 | | void SetCircularBufferSize(uint32_t aCapacity); |
212 | | |
213 | | private: |
214 | | // Helper for the Log() |
215 | | void UpdateCrashReport(); |
216 | | |
217 | | private: |
218 | | LoggingRecord mBuffer; |
219 | | CrashReporter::Annotation mCrashCriticalKey; |
220 | | uint32_t mMaxCapacity; |
221 | | int32_t mIndex; |
222 | | Mutex mMutex; |
223 | | }; |
224 | | |
225 | | CrashStatsLogForwarder::CrashStatsLogForwarder(CrashReporter::Annotation aKey) |
226 | | : mBuffer() |
227 | | , mCrashCriticalKey(aKey) |
228 | | , mMaxCapacity(0) |
229 | | , mIndex(-1) |
230 | | , mMutex("CrashStatsLogForwarder") |
231 | 0 | { |
232 | 0 | } |
233 | | |
234 | | void CrashStatsLogForwarder::SetCircularBufferSize(uint32_t aCapacity) |
235 | 0 | { |
236 | 0 | MutexAutoLock lock(mMutex); |
237 | 0 |
|
238 | 0 | mMaxCapacity = aCapacity; |
239 | 0 | mBuffer.reserve(static_cast<size_t>(aCapacity)); |
240 | 0 | } |
241 | | |
242 | | LoggingRecord |
243 | | CrashStatsLogForwarder::LoggingRecordCopy() |
244 | 0 | { |
245 | 0 | MutexAutoLock lock(mMutex); |
246 | 0 | return mBuffer; |
247 | 0 | } |
248 | | |
249 | | bool |
250 | | CrashStatsLogForwarder::UpdateStringsVector(const std::string& aString) |
251 | 0 | { |
252 | 0 | // We want at least the first one and the last one. Otherwise, no point. |
253 | 0 | if (mMaxCapacity < 2) { |
254 | 0 | return false; |
255 | 0 | } |
256 | 0 | |
257 | 0 | mIndex += 1; |
258 | 0 | MOZ_ASSERT(mIndex >= 0); |
259 | 0 |
|
260 | 0 | // index will count 0, 1, 2, ..., max-1, 1, 2, ..., max-1, 1, 2, ... |
261 | 0 | int32_t index = mIndex ? (mIndex-1) % (mMaxCapacity-1) + 1 : 0; |
262 | 0 | MOZ_ASSERT(index >= 0 && index < (int32_t)mMaxCapacity); |
263 | 0 | MOZ_ASSERT(index <= mIndex && index <= (int32_t)mBuffer.size()); |
264 | 0 |
|
265 | 0 | double tStamp = (TimeStamp::NowLoRes() - TimeStamp::ProcessCreation()).ToSecondsSigDigits(); |
266 | 0 |
|
267 | 0 | // Checking for index >= mBuffer.size(), rather than index == mBuffer.size() |
268 | 0 | // just out of paranoia, but we know index <= mBuffer.size(). |
269 | 0 | LoggingRecordEntry newEntry(mIndex,aString,tStamp); |
270 | 0 | if (index >= static_cast<int32_t>(mBuffer.size())) { |
271 | 0 | mBuffer.push_back(newEntry); |
272 | 0 | } else { |
273 | 0 | mBuffer[index] = newEntry; |
274 | 0 | } |
275 | 0 | return true; |
276 | 0 | } |
277 | | |
278 | | void CrashStatsLogForwarder::UpdateCrashReport() |
279 | 0 | { |
280 | 0 | std::stringstream message; |
281 | 0 | std::string logAnnotation; |
282 | 0 |
|
283 | 0 | switch (XRE_GetProcessType()) { |
284 | 0 | case GeckoProcessType_Default: |
285 | 0 | logAnnotation = "|["; |
286 | 0 | break; |
287 | 0 | case GeckoProcessType_Content: |
288 | 0 | logAnnotation = "|[C"; |
289 | 0 | break; |
290 | 0 | case GeckoProcessType_GPU: |
291 | 0 | logAnnotation = "|[G"; |
292 | 0 | break; |
293 | 0 | default: |
294 | 0 | logAnnotation = "|[X"; |
295 | 0 | break; |
296 | 0 | } |
297 | 0 | |
298 | 0 | for (auto& it : mBuffer) { |
299 | 0 | message << logAnnotation << Get<0>(it) << "]" << Get<1>(it) << " (t=" << Get<2>(it) << ") "; |
300 | 0 | } |
301 | 0 |
|
302 | 0 | nsCString reportString(message.str().c_str()); |
303 | 0 | nsresult annotated = CrashReporter::AnnotateCrashReport(mCrashCriticalKey, |
304 | 0 | reportString); |
305 | 0 |
|
306 | 0 | if (annotated != NS_OK) { |
307 | 0 | printf("Crash Annotation %s: %s", |
308 | 0 | CrashReporter::AnnotationToString(mCrashCriticalKey), |
309 | 0 | message.str().c_str()); |
310 | 0 | } |
311 | 0 | } |
312 | | |
313 | | class LogForwarderEvent : public Runnable |
314 | | { |
315 | 0 | ~LogForwarderEvent() override = default; |
316 | | |
317 | | public: |
318 | | NS_INLINE_DECL_REFCOUNTING_INHERITED(LogForwarderEvent, Runnable) |
319 | | |
320 | | explicit LogForwarderEvent(const nsCString& aMessage) |
321 | | : mozilla::Runnable("LogForwarderEvent") |
322 | | , mMessage(aMessage) |
323 | 0 | { |
324 | 0 | } |
325 | | |
326 | 0 | NS_IMETHOD Run() override { |
327 | 0 | MOZ_ASSERT(NS_IsMainThread() && (XRE_IsContentProcess() || XRE_IsGPUProcess())); |
328 | 0 |
|
329 | 0 | if (XRE_IsContentProcess()) { |
330 | 0 | dom::ContentChild* cc = dom::ContentChild::GetSingleton(); |
331 | 0 | Unused << cc->SendGraphicsError(mMessage); |
332 | 0 | } else if (XRE_IsGPUProcess()) { |
333 | 0 | GPUParent* gp = GPUParent::GetSingleton(); |
334 | 0 | Unused << gp->SendGraphicsError(mMessage); |
335 | 0 | } |
336 | 0 |
|
337 | 0 | return NS_OK; |
338 | 0 | } |
339 | | |
340 | | protected: |
341 | | nsCString mMessage; |
342 | | }; |
343 | | |
344 | | void CrashStatsLogForwarder::Log(const std::string& aString) |
345 | 0 | { |
346 | 0 | MutexAutoLock lock(mMutex); |
347 | 0 |
|
348 | 0 | if (UpdateStringsVector(aString)) { |
349 | 0 | UpdateCrashReport(); |
350 | 0 | } |
351 | 0 |
|
352 | 0 | // Add it to the parent strings |
353 | 0 | if (!XRE_IsParentProcess()) { |
354 | 0 | nsCString stringToSend(aString.c_str()); |
355 | 0 | if (NS_IsMainThread()) { |
356 | 0 | if (XRE_IsContentProcess()) { |
357 | 0 | dom::ContentChild* cc = dom::ContentChild::GetSingleton(); |
358 | 0 | Unused << cc->SendGraphicsError(stringToSend); |
359 | 0 | } else if (XRE_IsGPUProcess()) { |
360 | 0 | GPUParent* gp = GPUParent::GetSingleton(); |
361 | 0 | Unused << gp->SendGraphicsError(stringToSend); |
362 | 0 | } |
363 | 0 | } else { |
364 | 0 | nsCOMPtr<nsIRunnable> r1 = new LogForwarderEvent(stringToSend); |
365 | 0 | NS_DispatchToMainThread(r1); |
366 | 0 | } |
367 | 0 | } |
368 | 0 | } |
369 | | |
370 | | class CrashTelemetryEvent : public Runnable |
371 | | { |
372 | | ~CrashTelemetryEvent() override = default; |
373 | | |
374 | | public: |
375 | | NS_INLINE_DECL_REFCOUNTING_INHERITED(CrashTelemetryEvent, Runnable) |
376 | | |
377 | | explicit CrashTelemetryEvent(uint32_t aReason) |
378 | | : mozilla::Runnable("CrashTelemetryEvent") |
379 | | , mReason(aReason) |
380 | 0 | { |
381 | 0 | } |
382 | | |
383 | 0 | NS_IMETHOD Run() override { |
384 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
385 | 0 | Telemetry::Accumulate(Telemetry::GFX_CRASH, mReason); |
386 | 0 | return NS_OK; |
387 | 0 | } |
388 | | |
389 | | protected: |
390 | | uint32_t mReason; |
391 | | }; |
392 | | |
393 | | void |
394 | | CrashStatsLogForwarder::CrashAction(LogReason aReason) |
395 | 0 | { |
396 | 0 | #ifndef RELEASE_OR_BETA |
397 | 0 | // Non-release builds crash by default, but will use telemetry |
398 | 0 | // if this environment variable is present. |
399 | 0 | static bool useTelemetry = gfxEnv::GfxDevCrashTelemetry(); |
400 | | #else |
401 | | // Release builds use telemetry by default, but will crash instead |
402 | | // if this environment variable is present. |
403 | | static bool useTelemetry = !gfxEnv::GfxDevCrashMozCrash(); |
404 | | #endif |
405 | |
|
406 | 0 | if (useTelemetry) { |
407 | 0 | // The callers need to assure that aReason is in the range |
408 | 0 | // that the telemetry call below supports. |
409 | 0 | if (NS_IsMainThread()) { |
410 | 0 | Telemetry::Accumulate(Telemetry::GFX_CRASH, (uint32_t)aReason); |
411 | 0 | } else { |
412 | 0 | nsCOMPtr<nsIRunnable> r1 = new CrashTelemetryEvent((uint32_t)aReason); |
413 | 0 | NS_DispatchToMainThread(r1); |
414 | 0 | } |
415 | 0 | } else { |
416 | 0 | // ignoring aReason, we can get the information we need from the stack |
417 | 0 | MOZ_CRASH("GFX_CRASH"); |
418 | 0 | } |
419 | 0 | } |
420 | | |
421 | | NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference) |
422 | | |
423 | 0 | #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled" |
424 | | |
425 | 0 | #define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps" |
426 | | |
427 | 0 | #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled" |
428 | | |
429 | 0 | #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit" |
430 | 0 | #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries" |
431 | | |
432 | 0 | #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled" |
433 | | |
434 | 0 | #define BIDI_NUMERAL_PREF "bidi.numeral" |
435 | | |
436 | 0 | #define GFX_PREF_CMS_FORCE_SRGB "gfx.color_management.force_srgb" |
437 | | |
438 | 0 | #define FONT_VARIATIONS_PREF "layout.css.font-variations.enabled" |
439 | | |
440 | | NS_IMETHODIMP |
441 | | SRGBOverrideObserver::Observe(nsISupports *aSubject, |
442 | | const char *aTopic, |
443 | | const char16_t* someData) |
444 | 0 | { |
445 | 0 | NS_ASSERTION(NS_strcmp(someData, |
446 | 0 | (u"" GFX_PREF_CMS_FORCE_SRGB)) == 0, |
447 | 0 | "Restarting CMS on wrong pref!"); |
448 | 0 | ShutdownCMS(); |
449 | 0 | // Update current cms profile. |
450 | 0 | gfxPlatform::CreateCMSOutputProfile(); |
451 | 0 | return NS_OK; |
452 | 0 | } |
453 | | |
454 | | static const char* kObservedPrefs[] = { |
455 | | "gfx.downloadable_fonts.", |
456 | | "gfx.font_rendering.", |
457 | | BIDI_NUMERAL_PREF, |
458 | | nullptr |
459 | | }; |
460 | | |
461 | | static void |
462 | | FontPrefChanged(const char* aPref, void* aData) |
463 | 0 | { |
464 | 0 | MOZ_ASSERT(aPref); |
465 | 0 | NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone"); |
466 | 0 | gfxPlatform::GetPlatform()->FontsPrefsChanged(aPref); |
467 | 0 | } |
468 | | |
469 | | void |
470 | | gfxPlatform::OnMemoryPressure(layers::MemoryPressureReason aWhy) |
471 | 0 | { |
472 | 0 | Factory::PurgeAllCaches(); |
473 | 0 | gfxGradientCache::PurgeAllCaches(); |
474 | 0 | gfxFontMissingGlyphs::Purge(); |
475 | 0 | PurgeSkiaFontCache(); |
476 | 0 | PurgeSkiaGPUCache(); |
477 | 0 | if (XRE_IsParentProcess()) { |
478 | 0 | layers::CompositorManagerChild* manager = CompositorManagerChild::GetInstance(); |
479 | 0 | if (manager) { |
480 | 0 | manager->SendNotifyMemoryPressure(); |
481 | 0 | } |
482 | 0 | } |
483 | 0 | } |
484 | | |
485 | | gfxPlatform::gfxPlatform() |
486 | | : mHasVariationFontSupport(false) |
487 | | , mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo) |
488 | | , mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo) |
489 | | , mTilesInfoCollector(this, &gfxPlatform::GetTilesSupportInfo) |
490 | | , mCompositorBackend(layers::LayersBackend::LAYERS_NONE) |
491 | | , mScreenDepth(0) |
492 | 0 | { |
493 | 0 | mAllowDownloadableFonts = UNINITIALIZED_VALUE; |
494 | 0 | mFallbackUsesCmaps = UNINITIALIZED_VALUE; |
495 | 0 |
|
496 | 0 | mWordCacheCharLimit = UNINITIALIZED_VALUE; |
497 | 0 | mWordCacheMaxEntries = UNINITIALIZED_VALUE; |
498 | 0 | mGraphiteShapingEnabled = UNINITIALIZED_VALUE; |
499 | 0 | mOpenTypeSVGEnabled = UNINITIALIZED_VALUE; |
500 | 0 | mBidiNumeralOption = UNINITIALIZED_VALUE; |
501 | 0 |
|
502 | 0 | mSkiaGlue = nullptr; |
503 | 0 |
|
504 | 0 | InitBackendPrefs(GetBackendPrefs()); |
505 | 0 |
|
506 | 0 | mTotalSystemMemory = PR_GetPhysicalMemorySize(); |
507 | 0 |
|
508 | 0 | VRManager::ManagerInit(); |
509 | 0 | } |
510 | | |
511 | | gfxPlatform* |
512 | | gfxPlatform::GetPlatform() |
513 | 0 | { |
514 | 0 | if (!gPlatform) { |
515 | 0 | MOZ_RELEASE_ASSERT(!XRE_IsContentProcess(), |
516 | 0 | "Content Process should have called InitChild() before first GetPlatform()"); |
517 | 0 | Init(); |
518 | 0 | } |
519 | 0 | return gPlatform; |
520 | 0 | } |
521 | | |
522 | | bool |
523 | | gfxPlatform::Initialized() |
524 | 0 | { |
525 | 0 | return !!gPlatform; |
526 | 0 | } |
527 | | |
528 | | /* static */ void |
529 | | gfxPlatform::InitChild(const ContentDeviceData& aData) |
530 | 0 | { |
531 | 0 | MOZ_ASSERT(XRE_IsContentProcess()); |
532 | 0 | MOZ_RELEASE_ASSERT(!gPlatform, |
533 | 0 | "InitChild() should be called before first GetPlatform()"); |
534 | 0 | // Make the provided initial ContentDeviceData available to the init |
535 | 0 | // routines, so they don't have to do a sync request from the parent. |
536 | 0 | gContentDeviceInitData = &aData; |
537 | 0 | Init(); |
538 | 0 | gContentDeviceInitData = nullptr; |
539 | 0 | } |
540 | | |
541 | | void RecordingPrefChanged(const char *aPrefName, void *aClosure) |
542 | 0 | { |
543 | 0 | if (Preferences::GetBool("gfx.2d.recording", false)) { |
544 | 0 | nsAutoCString fileName; |
545 | 0 | nsAutoString prefFileName; |
546 | 0 | nsresult rv = Preferences::GetString("gfx.2d.recordingfile", prefFileName); |
547 | 0 | if (NS_SUCCEEDED(rv)) { |
548 | 0 | CopyUTF16toUTF8(prefFileName, fileName); |
549 | 0 | } else { |
550 | 0 | nsCOMPtr<nsIFile> tmpFile; |
551 | 0 | if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)))) { |
552 | 0 | return; |
553 | 0 | } |
554 | 0 | fileName.AppendPrintf("moz2drec_%i_%i.aer", XRE_GetProcessType(), getpid()); |
555 | 0 |
|
556 | 0 | nsresult rv = tmpFile->AppendNative(fileName); |
557 | 0 | if (NS_FAILED(rv)) |
558 | 0 | return; |
559 | 0 | |
560 | | #ifdef XP_WIN |
561 | | rv = tmpFile->GetPath(prefFileName); |
562 | | CopyUTF16toUTF8(prefFileName, fileName); |
563 | | #else |
564 | 0 | rv = tmpFile->GetNativePath(fileName); |
565 | 0 | #endif |
566 | 0 | if (NS_FAILED(rv)) |
567 | 0 | return; |
568 | 0 | } |
569 | 0 | |
570 | | #ifdef XP_WIN |
571 | | gPlatform->mRecorder = Factory::CreateEventRecorderForFile(prefFileName.BeginReading()); |
572 | | #else |
573 | 0 | gPlatform->mRecorder = Factory::CreateEventRecorderForFile(fileName.BeginReading()); |
574 | 0 | #endif |
575 | 0 | printf_stderr("Recording to %s\n", fileName.get()); |
576 | 0 | Factory::SetGlobalEventRecorder(gPlatform->mRecorder); |
577 | 0 | } else { |
578 | 0 | Factory::SetGlobalEventRecorder(nullptr); |
579 | 0 | } |
580 | 0 | } |
581 | | |
582 | 0 | #define WR_DEBUG_PREF "gfx.webrender.debug" |
583 | | |
584 | | void |
585 | | WebRenderDebugPrefChangeCallback(const char* aPrefName, void*) |
586 | 0 | { |
587 | 0 | int32_t flags = 0; |
588 | 0 | #define GFX_WEBRENDER_DEBUG(suffix, bit) \ |
589 | 0 | if (Preferences::GetBool(WR_DEBUG_PREF suffix, false)) { \ |
590 | 0 | flags |= (bit); \ |
591 | 0 | } |
592 | 0 |
|
593 | 0 | // TODO: It would be nice to get the bit patterns directly from the rust code. |
594 | 0 | GFX_WEBRENDER_DEBUG(".profiler", 1 << 0) |
595 | 0 | GFX_WEBRENDER_DEBUG(".render-targets", 1 << 1) |
596 | 0 | GFX_WEBRENDER_DEBUG(".texture-cache", 1 << 2) |
597 | 0 | GFX_WEBRENDER_DEBUG(".gpu-time-queries", 1 << 3) |
598 | 0 | GFX_WEBRENDER_DEBUG(".gpu-sample-queries", 1 << 4) |
599 | 0 | GFX_WEBRENDER_DEBUG(".disable-batching", 1 << 5) |
600 | 0 | GFX_WEBRENDER_DEBUG(".epochs", 1 << 6) |
601 | 0 | GFX_WEBRENDER_DEBUG(".compact-profiler", 1 << 7) |
602 | 0 | GFX_WEBRENDER_DEBUG(".echo-driver-messages", 1 << 8) |
603 | 0 | GFX_WEBRENDER_DEBUG(".new-frame-indicator", 1 << 9) |
604 | 0 | GFX_WEBRENDER_DEBUG(".new-scene-indicator", 1 << 10) |
605 | 0 | GFX_WEBRENDER_DEBUG(".show-overdraw", 1 << 11) |
606 | 0 | #undef GFX_WEBRENDER_DEBUG |
607 | 0 |
|
608 | 0 | gfx::gfxVars::SetWebRenderDebugFlags(flags); |
609 | 0 | } |
610 | | |
611 | | |
612 | | #if defined(USE_SKIA) |
613 | | static uint32_t GetSkiaGlyphCacheSize() |
614 | 0 | { |
615 | 0 | // Only increase font cache size on non-android to save memory. |
616 | 0 | #if !defined(MOZ_WIDGET_ANDROID) |
617 | 0 | // 10mb as the default pref cache size on desktop due to talos perf tweaking. |
618 | 0 | // Chromium uses 20mb and skia default uses 2mb. |
619 | 0 | // We don't need to change the font cache count since we usually |
620 | 0 | // cache thrash due to asian character sets in talos. |
621 | 0 | // Only increase memory on the content process |
622 | 0 | uint32_t cacheSize = gfxPrefs::SkiaContentFontCacheSize() * 1024 * 1024; |
623 | 0 | if (mozilla::BrowserTabsRemoteAutostart()) { |
624 | 0 | return XRE_IsContentProcess() ? cacheSize : kDefaultGlyphCacheSize; |
625 | 0 | } |
626 | 0 |
|
627 | 0 | return cacheSize; |
628 | | #else |
629 | | return kDefaultGlyphCacheSize; |
630 | | #endif // MOZ_WIDGET_ANDROID |
631 | | } |
632 | | #endif |
633 | | |
634 | | class WebRenderMemoryReporter final : public nsIMemoryReporter { |
635 | | public: |
636 | | NS_DECL_ISUPPORTS |
637 | | NS_DECL_NSIMEMORYREPORTER |
638 | | |
639 | | private: |
640 | | ~WebRenderMemoryReporter() = default; |
641 | | }; |
642 | | |
643 | | // Memory reporter for WebRender. |
644 | | // |
645 | | // The reporting within WebRender is manual and incomplete. We could do a much |
646 | | // more thorough job by depending on the malloc_size_of crate, but integrating |
647 | | // that into WebRender is tricky [1]. |
648 | | // |
649 | | // So the idea is to start with manual reporting for the large allocations |
650 | | // detected by DMD, and see how much that can cover in practice (which may |
651 | | // require a few rounds of iteration). If that approach turns out to be |
652 | | // fundamentally insufficient, we can either duplicate more of the malloc_size_of |
653 | | // functionality in WebRender, or deal with the complexity of a gecko-only |
654 | | // crate dependency. |
655 | | // |
656 | | // [1] See https://bugzilla.mozilla.org/show_bug.cgi?id=1480293#c1 |
657 | | struct WebRenderMemoryReporterHelper { |
658 | | WebRenderMemoryReporterHelper(nsIHandleReportCallback* aCallback, nsISupports* aData) |
659 | | : mCallback(aCallback), mData(aData) |
660 | 0 | {} |
661 | | nsCOMPtr<nsIHandleReportCallback> mCallback; |
662 | | nsCOMPtr<nsISupports> mData; |
663 | | |
664 | | void Report(size_t aBytes, const char* aName) const |
665 | 0 | { |
666 | 0 | // Generally, memory reporters pass the empty string as the process name to |
667 | 0 | // indicate "current process". However, if we're using a GPU process, the |
668 | 0 | // measurements will actually take place in that process, and it's easier to |
669 | 0 | // just note that here rather than trying to invoke the memory reporter in |
670 | 0 | // the GPU process. |
671 | 0 | nsAutoCString processName; |
672 | 0 | if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { |
673 | 0 | GPUParent::GetGPUProcessName(processName); |
674 | 0 | } |
675 | 0 |
|
676 | 0 | nsPrintfCString path("explicit/gfx/webrender/%s", aName); |
677 | 0 | mCallback->Callback(processName, path, |
678 | 0 | nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES, |
679 | 0 | aBytes, EmptyCString(), mData); |
680 | 0 | } |
681 | | }; |
682 | | |
683 | | static void |
684 | | FinishAsyncMemoryReport() |
685 | 0 | { |
686 | 0 | nsCOMPtr<nsIMemoryReporterManager> imgr = |
687 | 0 | do_GetService("@mozilla.org/memory-reporter-manager;1"); |
688 | 0 | if (imgr) { |
689 | 0 | imgr->EndReport(); |
690 | 0 | } |
691 | 0 | } |
692 | | |
693 | | NS_IMPL_ISUPPORTS(WebRenderMemoryReporter, nsIMemoryReporter) |
694 | | |
695 | | NS_IMETHODIMP |
696 | | WebRenderMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport, |
697 | | nsISupports* aData, bool aAnonymize) |
698 | 0 | { |
699 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
700 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
701 | 0 | layers::CompositorManagerChild* manager = CompositorManagerChild::GetInstance(); |
702 | 0 | if (!manager) { |
703 | 0 | FinishAsyncMemoryReport(); |
704 | 0 | return NS_OK; |
705 | 0 | } |
706 | 0 | |
707 | 0 | WebRenderMemoryReporterHelper helper(aHandleReport, aData); |
708 | 0 | manager->SendReportMemory( |
709 | 0 | [=](wr::MemoryReport aReport) { |
710 | 0 | helper.Report(aReport.primitive_stores, "primitive-stores"); |
711 | 0 | helper.Report(aReport.clip_stores, "clip-stores"); |
712 | 0 | helper.Report(aReport.gpu_cache_metadata, "gpu-cache/metadata"); |
713 | 0 | helper.Report(aReport.gpu_cache_cpu_mirror, "gpu-cache/cpu-mirror"); |
714 | 0 | helper.Report(aReport.render_tasks, "render-tasks"); |
715 | 0 | helper.Report(aReport.hit_testers, "hit-testers"); |
716 | 0 | helper.Report(aReport.fonts, "resource-cache/font"); |
717 | 0 | helper.Report(aReport.images, "resource-cache/images"); |
718 | 0 | helper.Report(aReport.rasterized_blobs, "resource-cache/rasterized-blobs"); |
719 | 0 | FinishAsyncMemoryReport(); |
720 | 0 | }, |
721 | 0 | [](mozilla::ipc::ResponseRejectReason aReason) { |
722 | 0 | FinishAsyncMemoryReport(); |
723 | 0 | } |
724 | 0 | ); |
725 | 0 |
|
726 | 0 | return NS_OK; |
727 | 0 | } |
728 | | |
729 | | |
730 | | void |
731 | | gfxPlatform::Init() |
732 | 0 | { |
733 | 0 | MOZ_RELEASE_ASSERT(!XRE_IsGPUProcess(), "GFX: Not allowed in GPU process."); |
734 | 0 | MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread."); |
735 | 0 |
|
736 | 0 | if (gEverInitialized) { |
737 | 0 | MOZ_CRASH("Already started???"); |
738 | 0 | } |
739 | 0 | gEverInitialized = true; |
740 | 0 |
|
741 | 0 | // Initialize the preferences by creating the singleton. |
742 | 0 | gfxPrefs::GetSingleton(); |
743 | 0 | gfxVars::Initialize(); |
744 | 0 |
|
745 | 0 | gfxConfig::Init(); |
746 | 0 |
|
747 | 0 | if (XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()) { |
748 | 0 | GPUProcessManager::Initialize(); |
749 | 0 |
|
750 | 0 | if (Preferences::GetBool("media.wmf.skip-blacklist")) { |
751 | 0 | gfxVars::SetPDMWMFDisableD3D11Dlls(nsCString()); |
752 | 0 | gfxVars::SetPDMWMFDisableD3D9Dlls(nsCString()); |
753 | 0 | } else { |
754 | 0 | nsAutoCString d3d11; |
755 | 0 | Preferences::GetCString("media.wmf.disable-d3d11-for-dlls", d3d11); |
756 | 0 | gfxVars::SetPDMWMFDisableD3D11Dlls(d3d11); |
757 | 0 | nsAutoCString d3d9; |
758 | 0 | Preferences::GetCString("media.wmf.disable-d3d9-for-dlls", d3d9); |
759 | 0 | gfxVars::SetPDMWMFDisableD3D9Dlls(d3d9); |
760 | 0 | } |
761 | 0 |
|
762 | 0 | nsCOMPtr<nsIFile> file; |
763 | 0 | nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file)); |
764 | 0 | if (NS_FAILED(rv)) { |
765 | 0 | gfxVars::SetGREDirectory(nsString()); |
766 | 0 | } else { |
767 | 0 | nsAutoString path; |
768 | 0 | file->GetPath(path); |
769 | 0 | gfxVars::SetGREDirectory(nsString(path)); |
770 | 0 | } |
771 | 0 | } |
772 | 0 |
|
773 | 0 | // Drop a note in the crash report if we end up forcing an option that could |
774 | 0 | // destabilize things. New items should be appended at the end (of an existing |
775 | 0 | // or in a new section), so that we don't have to know the version to interpret |
776 | 0 | // these cryptic strings. |
777 | 0 | { |
778 | 0 | nsAutoCString forcedPrefs; |
779 | 0 | // D2D prefs |
780 | 0 | forcedPrefs.AppendPrintf("FP(D%d%d", |
781 | 0 | gfxPrefs::Direct2DDisabled(), |
782 | 0 | gfxPrefs::Direct2DForceEnabled()); |
783 | 0 | // Layers prefs |
784 | 0 | forcedPrefs.AppendPrintf("-L%d%d%d%d", |
785 | 0 | gfxPrefs::LayersAMDSwitchableGfxEnabled(), |
786 | 0 | gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly(), |
787 | 0 | gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly(), |
788 | 0 | gfxPrefs::LayersD3D11ForceWARP()); |
789 | 0 | // WebGL prefs |
790 | 0 | forcedPrefs.AppendPrintf("-W%d%d%d%d%d%d%d%d", |
791 | 0 | gfxPrefs::WebGLANGLEForceD3D11(), |
792 | 0 | gfxPrefs::WebGLANGLEForceWARP(), |
793 | 0 | gfxPrefs::WebGLDisabled(), |
794 | 0 | gfxPrefs::WebGLDisableANGLE(), |
795 | 0 | gfxPrefs::WebGLDXGLEnabled(), |
796 | 0 | gfxPrefs::WebGLForceEnabled(), |
797 | 0 | gfxPrefs::WebGLForceLayersReadback(), |
798 | 0 | gfxPrefs::WebGLForceMSAA()); |
799 | 0 | // Prefs that don't fit into any of the other sections |
800 | 0 | forcedPrefs.AppendPrintf("-T%d%d%d) ", |
801 | 0 | gfxPrefs::AndroidRGB16Force(), |
802 | 0 | gfxPrefs::CanvasAzureAccelerated(), |
803 | 0 | gfxPrefs::ForceShmemTiles()); |
804 | 0 | ScopedGfxFeatureReporter::AppNote(forcedPrefs); |
805 | 0 | } |
806 | 0 |
|
807 | 0 | InitMoz2DLogging(); |
808 | 0 |
|
809 | 0 | gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock"); |
810 | 0 |
|
811 | 0 | /* Initialize the GfxInfo service. |
812 | 0 | * Note: we can't call functions on GfxInfo that depend |
813 | 0 | * on gPlatform until after it has been initialized |
814 | 0 | * below. GfxInfo initialization annotates our |
815 | 0 | * crash reports so we want to do it before |
816 | 0 | * we try to load any drivers and do device detection |
817 | 0 | * incase that code crashes. See bug #591561. */ |
818 | 0 | nsCOMPtr<nsIGfxInfo> gfxInfo; |
819 | 0 | /* this currently will only succeed on Windows */ |
820 | 0 | gfxInfo = services::GetGfxInfo(); |
821 | 0 |
|
822 | | #if defined(XP_WIN) |
823 | | gPlatform = new gfxWindowsPlatform; |
824 | | #elif defined(XP_MACOSX) |
825 | | gPlatform = new gfxPlatformMac; |
826 | | #elif defined(MOZ_WIDGET_GTK) |
827 | | gPlatform = new gfxPlatformGtk; |
828 | | #elif defined(ANDROID) |
829 | | gPlatform = new gfxAndroidPlatform; |
830 | | #else |
831 | | #error "No gfxPlatform implementation available" |
832 | | #endif |
833 | | gPlatform->InitAcceleration(); |
834 | 0 | gPlatform->InitWebRenderConfig(); |
835 | 0 | gPlatform->InitOMTPConfig(); |
836 | 0 |
|
837 | 0 | if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { |
838 | 0 | GPUProcessManager* gpu = GPUProcessManager::Get(); |
839 | 0 | gpu->LaunchGPUProcess(); |
840 | 0 | } |
841 | 0 |
|
842 | 0 | if (XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()) { |
843 | 0 | if (gfxPlatform::ForceSoftwareVsync()) { |
844 | 0 | gPlatform->mVsyncSource = (gPlatform)->gfxPlatform::CreateHardwareVsyncSource(); |
845 | 0 | } else { |
846 | 0 | gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource(); |
847 | 0 | } |
848 | 0 | } |
849 | 0 |
|
850 | 0 | #ifdef USE_SKIA |
851 | 0 | SkGraphics::Init(); |
852 | 0 | # ifdef MOZ_ENABLE_FREETYPE |
853 | 0 | SkInitCairoFT(gPlatform->FontHintingEnabled()); |
854 | 0 | # endif |
855 | 0 | #endif |
856 | 0 |
|
857 | 0 | InitLayersIPC(); |
858 | 0 |
|
859 | 0 | gPlatform->PopulateScreenInfo(); |
860 | 0 | gPlatform->ComputeTileSize(); |
861 | 0 |
|
862 | 0 | #ifdef MOZ_ENABLE_FREETYPE |
863 | 0 | Factory::SetFTLibrary(gPlatform->GetFTLibrary()); |
864 | 0 | #endif |
865 | 0 |
|
866 | 0 | gPlatform->mHasVariationFontSupport = |
867 | 0 | gPlatform->CheckVariationFontSupport(); |
868 | 0 |
|
869 | 0 | nsresult rv; |
870 | 0 | rv = gfxPlatformFontList::Init(); |
871 | 0 | if (NS_FAILED(rv)) { |
872 | 0 | MOZ_CRASH("Could not initialize gfxPlatformFontList"); |
873 | 0 | } |
874 | 0 |
|
875 | 0 | gPlatform->mScreenReferenceSurface = |
876 | 0 | gPlatform->CreateOffscreenSurface(IntSize(1, 1), |
877 | 0 | SurfaceFormat::A8R8G8B8_UINT32); |
878 | 0 | if (!gPlatform->mScreenReferenceSurface) { |
879 | 0 | MOZ_CRASH("Could not initialize mScreenReferenceSurface"); |
880 | 0 | } |
881 | 0 |
|
882 | 0 | gPlatform->mScreenReferenceDrawTarget = |
883 | 0 | gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1), |
884 | 0 | SurfaceFormat::B8G8R8A8); |
885 | 0 | if (!gPlatform->mScreenReferenceDrawTarget || |
886 | 0 | !gPlatform->mScreenReferenceDrawTarget->IsValid()) { |
887 | 0 | // If TDR is detected, create a draw target with software backend |
888 | 0 | // and it should be replaced later when the process gets the device |
889 | 0 | // reset notification. |
890 | 0 | if (!gPlatform->DidRenderingDeviceReset()) { |
891 | 0 | gfxCriticalError() << "Could not initialize mScreenReferenceDrawTarget"; |
892 | 0 | } |
893 | 0 | } |
894 | 0 |
|
895 | 0 | rv = gfxFontCache::Init(); |
896 | 0 | if (NS_FAILED(rv)) { |
897 | 0 | MOZ_CRASH("Could not initialize gfxFontCache"); |
898 | 0 | } |
899 | 0 |
|
900 | 0 | /* Create and register our CMS Override observer. */ |
901 | 0 | gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver(); |
902 | 0 | Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB); |
903 | 0 |
|
904 | 0 | Preferences::RegisterPrefixCallbacks(FontPrefChanged, kObservedPrefs); |
905 | 0 |
|
906 | 0 | GLContext::PlatformStartup(); |
907 | 0 |
|
908 | 0 | Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording"); |
909 | 0 |
|
910 | 0 | CreateCMSOutputProfile(); |
911 | 0 |
|
912 | 0 | // Listen to memory pressure event so we can purge DrawTarget caches |
913 | 0 | gPlatform->mMemoryPressureObserver = layers::MemoryPressureObserver::Create(gPlatform); |
914 | 0 |
|
915 | 0 | // Request the imgITools service, implicitly initializing ImageLib. |
916 | 0 | nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1"); |
917 | 0 | if (!imgTools) { |
918 | 0 | MOZ_CRASH("Could not initialize ImageLib"); |
919 | 0 | } |
920 | 0 |
|
921 | 0 | RegisterStrongMemoryReporter(new GfxMemoryImageReporter()); |
922 | 0 | if (XRE_IsParentProcess() && gfxVars::UseWebRender()) { |
923 | 0 | RegisterStrongAsyncMemoryReporter(new WebRenderMemoryReporter()); |
924 | 0 | } |
925 | 0 |
|
926 | 0 | #ifdef USE_SKIA |
927 | 0 | RegisterStrongMemoryReporter(new SkMemoryReporter()); |
928 | 0 | #endif |
929 | 0 | mlg::InitializeMemoryReporters(); |
930 | 0 |
|
931 | 0 | #ifdef USE_SKIA |
932 | 0 | uint32_t skiaCacheSize = GetSkiaGlyphCacheSize(); |
933 | 0 | if (skiaCacheSize != kDefaultGlyphCacheSize) { |
934 | 0 | SkGraphics::SetFontCacheLimit(skiaCacheSize); |
935 | 0 | } |
936 | 0 | #endif |
937 | 0 |
|
938 | 0 | InitNullMetadata(); |
939 | 0 | InitOpenGLConfig(); |
940 | 0 |
|
941 | 0 | if (XRE_IsParentProcess()) { |
942 | 0 | gfxVars::SetDXInterop2Blocked(IsDXInterop2Blocked()); |
943 | 0 | gfxVars::SetDXNV12Blocked(IsDXNV12Blocked()); |
944 | 0 | Preferences::Unlock(FONT_VARIATIONS_PREF); |
945 | 0 | if (!gPlatform->HasVariationFontSupport()) { |
946 | 0 | // Ensure variation fonts are disabled and the pref is locked. |
947 | 0 | Preferences::SetBool(FONT_VARIATIONS_PREF, false, |
948 | 0 | PrefValueKind::Default); |
949 | 0 | Preferences::SetBool(FONT_VARIATIONS_PREF, false); |
950 | 0 | Preferences::Lock(FONT_VARIATIONS_PREF); |
951 | 0 | } |
952 | 0 |
|
953 | 0 | nsCOMPtr<nsIFile> profDir; |
954 | 0 | rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, getter_AddRefs(profDir)); |
955 | 0 | if (NS_FAILED(rv)) { |
956 | 0 | gfxVars::SetProfDirectory(nsString()); |
957 | 0 | } else { |
958 | 0 | nsAutoString path; |
959 | 0 | profDir->GetPath(path); |
960 | 0 | gfxVars::SetProfDirectory(nsString(path)); |
961 | 0 | } |
962 | 0 |
|
963 | 0 | gfxUtils::RemoveShaderCacheFromDiskIfNecessary(); |
964 | 0 | } |
965 | 0 |
|
966 | 0 | nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
967 | 0 | if (obs) { |
968 | 0 | obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr); |
969 | 0 | } |
970 | 0 | } |
971 | | |
972 | | /* static*/ bool |
973 | | gfxPlatform::IsDXInterop2Blocked() |
974 | 0 | { |
975 | 0 | nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); |
976 | 0 | nsCString blockId; |
977 | 0 | int32_t status; |
978 | 0 | if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DX_INTEROP2, |
979 | 0 | blockId, &status))) { |
980 | 0 | return true; |
981 | 0 | } |
982 | 0 | return status != nsIGfxInfo::FEATURE_STATUS_OK; |
983 | 0 | } |
984 | | |
985 | | /* static*/ bool |
986 | | gfxPlatform::IsDXNV12Blocked() |
987 | 0 | { |
988 | 0 | nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); |
989 | 0 | nsCString blockId; |
990 | 0 | int32_t status; |
991 | 0 | if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DX_NV12, |
992 | 0 | blockId, &status))) { |
993 | 0 | return true; |
994 | 0 | } |
995 | 0 | return status != nsIGfxInfo::FEATURE_STATUS_OK; |
996 | 0 | } |
997 | | |
998 | | /* static */ int32_t |
999 | | gfxPlatform::MaxTextureSize() |
1000 | 0 | { |
1001 | 0 | // Make sure we don't completely break rendering because of a typo in the |
1002 | 0 | // pref or whatnot. |
1003 | 0 | const int32_t kMinSizePref = 2048; |
1004 | 0 | return std::max(kMinSizePref, gfxPrefs::MaxTextureSizeDoNotUseDirectly()); |
1005 | 0 | } |
1006 | | |
1007 | | /* static */ int32_t |
1008 | | gfxPlatform::MaxAllocSize() |
1009 | 0 | { |
1010 | 0 | // Make sure we don't completely break rendering because of a typo in the |
1011 | 0 | // pref or whatnot. |
1012 | 0 | const int32_t kMinAllocPref = 10000000; |
1013 | 0 | return std::max(kMinAllocPref, gfxPrefs::MaxAllocSizeDoNotUseDirectly()); |
1014 | 0 | } |
1015 | | |
1016 | | /* static */ void |
1017 | | gfxPlatform::InitMoz2DLogging() |
1018 | 0 | { |
1019 | 0 | auto fwd = new CrashStatsLogForwarder( |
1020 | 0 | CrashReporter::Annotation::GraphicsCriticalError); |
1021 | 0 | fwd->SetCircularBufferSize(gfxPrefs::GfxLoggingCrashLength()); |
1022 | 0 |
|
1023 | 0 | mozilla::gfx::Config cfg; |
1024 | 0 | cfg.mLogForwarder = fwd; |
1025 | 0 | cfg.mMaxTextureSize = gfxPlatform::MaxTextureSize(); |
1026 | 0 | cfg.mMaxAllocSize = gfxPlatform::MaxAllocSize(); |
1027 | 0 |
|
1028 | 0 | gfx::Factory::Init(cfg); |
1029 | 0 | } |
1030 | | |
1031 | | /* static */ bool |
1032 | | gfxPlatform::IsHeadless() |
1033 | 3 | { |
1034 | 3 | static bool initialized = false; |
1035 | 3 | static bool headless = false; |
1036 | 3 | if (!initialized) { |
1037 | 3 | initialized = true; |
1038 | 3 | headless = PR_GetEnv("MOZ_HEADLESS"); |
1039 | 3 | } |
1040 | 3 | return headless; |
1041 | 3 | } |
1042 | | |
1043 | | static bool sLayersIPCIsUp = false; |
1044 | | |
1045 | | /* static */ void |
1046 | | gfxPlatform::InitNullMetadata() |
1047 | 0 | { |
1048 | 0 | ScrollMetadata::sNullMetadata = new ScrollMetadata(); |
1049 | 0 | ClearOnShutdown(&ScrollMetadata::sNullMetadata); |
1050 | 0 | } |
1051 | | |
1052 | | void |
1053 | | gfxPlatform::Shutdown() |
1054 | 0 | { |
1055 | 0 | // In some cases, gPlatform may not be created but Shutdown() called, |
1056 | 0 | // e.g., during xpcshell tests. |
1057 | 0 | if (!gPlatform) { |
1058 | 0 | return; |
1059 | 0 | } |
1060 | 0 | |
1061 | 0 | MOZ_ASSERT(!sLayersIPCIsUp); |
1062 | 0 |
|
1063 | 0 | // These may be called before the corresponding subsystems have actually |
1064 | 0 | // started up. That's OK, they can handle it. |
1065 | 0 | gfxFontCache::Shutdown(); |
1066 | 0 | gfxGradientCache::Shutdown(); |
1067 | 0 | gfxAlphaBoxBlur::ShutdownBlurCache(); |
1068 | 0 | gfxGraphiteShaper::Shutdown(); |
1069 | 0 | gfxPlatformFontList::Shutdown(); |
1070 | 0 | gfxFontMissingGlyphs::Shutdown(); |
1071 | 0 | ShutdownTileCache(); |
1072 | 0 |
|
1073 | 0 | // Free the various non-null transforms and loaded profiles |
1074 | 0 | ShutdownCMS(); |
1075 | 0 |
|
1076 | 0 | /* Unregister our CMS Override callback. */ |
1077 | 0 | NS_ASSERTION(gPlatform->mSRGBOverrideObserver, "mSRGBOverrideObserver has alreay gone"); |
1078 | 0 | Preferences::RemoveObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB); |
1079 | 0 | gPlatform->mSRGBOverrideObserver = nullptr; |
1080 | 0 |
|
1081 | 0 | Preferences::UnregisterPrefixCallbacks(FontPrefChanged, kObservedPrefs); |
1082 | 0 |
|
1083 | 0 | NS_ASSERTION(gPlatform->mMemoryPressureObserver, "mMemoryPressureObserver has already gone"); |
1084 | 0 | if (gPlatform->mMemoryPressureObserver) { |
1085 | 0 | gPlatform->mMemoryPressureObserver->Unregister(); |
1086 | 0 | gPlatform->mMemoryPressureObserver = nullptr; |
1087 | 0 | } |
1088 | 0 | gPlatform->mSkiaGlue = nullptr; |
1089 | 0 |
|
1090 | 0 | if (XRE_IsParentProcess()) { |
1091 | 0 | gPlatform->mVsyncSource->Shutdown(); |
1092 | 0 | } |
1093 | 0 |
|
1094 | 0 | gPlatform->mVsyncSource = nullptr; |
1095 | 0 |
|
1096 | 0 | // Shut down the default GL context provider. |
1097 | 0 | GLContextProvider::Shutdown(); |
1098 | 0 |
|
1099 | | #if defined(XP_WIN) |
1100 | | // The above shutdown calls operate on the available context providers on |
1101 | | // most platforms. Windows is a "special snowflake", though, and has three |
1102 | | // context providers available, so we have to shut all of them down. |
1103 | | // We should only support the default GL provider on Windows; then, this |
1104 | | // could go away. Unfortunately, we currently support WGL (the default) for |
1105 | | // WebGL on Optimus. |
1106 | | GLContextProviderEGL::Shutdown(); |
1107 | | #endif |
1108 | |
|
1109 | 0 | if (XRE_IsParentProcess()) { |
1110 | 0 | GPUProcessManager::Shutdown(); |
1111 | 0 | VRProcessManager::Shutdown(); |
1112 | 0 | } |
1113 | 0 |
|
1114 | 0 | gfx::Factory::ShutDown(); |
1115 | 0 |
|
1116 | 0 | delete gGfxPlatformPrefsLock; |
1117 | 0 |
|
1118 | 0 | gfxVars::Shutdown(); |
1119 | 0 | gfxPrefs::DestroySingleton(); |
1120 | 0 | gfxFont::DestroySingletons(); |
1121 | 0 |
|
1122 | 0 | gfxConfig::Shutdown(); |
1123 | 0 |
|
1124 | 0 | gPlatform->WillShutdown(); |
1125 | 0 |
|
1126 | 0 | delete gPlatform; |
1127 | 0 | gPlatform = nullptr; |
1128 | 0 | } |
1129 | | |
1130 | | /* static */ void |
1131 | | gfxPlatform::InitLayersIPC() |
1132 | 0 | { |
1133 | 0 | if (sLayersIPCIsUp) { |
1134 | 0 | return; |
1135 | 0 | } |
1136 | 0 | sLayersIPCIsUp = true; |
1137 | 0 |
|
1138 | 0 | if (XRE_IsContentProcess()) { |
1139 | 0 | if (gfxVars::UseOMTP() && !recordreplay::IsRecordingOrReplaying()) { |
1140 | 0 | layers::PaintThread::Start(); |
1141 | 0 | } |
1142 | 0 | } |
1143 | 0 |
|
1144 | 0 | if (XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()) { |
1145 | 0 | if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS) && gfxVars::UseWebRender()) { |
1146 | 0 | wr::RenderThread::Start(); |
1147 | 0 | } |
1148 | 0 |
|
1149 | 0 | layers::CompositorThreadHolder::Start(); |
1150 | 0 | gfx::VRListenerThreadHolder::Start(); |
1151 | 0 | } |
1152 | 0 | } |
1153 | | |
1154 | | /* static */ void |
1155 | | gfxPlatform::ShutdownLayersIPC() |
1156 | 0 | { |
1157 | 0 | if (!sLayersIPCIsUp) { |
1158 | 0 | return; |
1159 | 0 | } |
1160 | 0 | sLayersIPCIsUp = false; |
1161 | 0 |
|
1162 | 0 | if (XRE_IsContentProcess()) { |
1163 | 0 | gfx::VRManagerChild::ShutDown(); |
1164 | 0 | // cf bug 1215265. |
1165 | 0 | if (gfxPrefs::ChildProcessShutdown()) { |
1166 | 0 | layers::CompositorManagerChild::Shutdown(); |
1167 | 0 | layers::ImageBridgeChild::ShutDown(); |
1168 | 0 | } |
1169 | 0 |
|
1170 | 0 | if (gfxVars::UseOMTP() && !recordreplay::IsRecordingOrReplaying()) { |
1171 | 0 | layers::PaintThread::Shutdown(); |
1172 | 0 | } |
1173 | 0 | } else if (XRE_IsParentProcess()) { |
1174 | 0 | gfx::VRManagerChild::ShutDown(); |
1175 | 0 | layers::CompositorManagerChild::Shutdown(); |
1176 | 0 | layers::ImageBridgeChild::ShutDown(); |
1177 | 0 | // This has to happen after shutting down the child protocols. |
1178 | 0 | layers::CompositorThreadHolder::Shutdown(); |
1179 | 0 | gfx::VRListenerThreadHolder::Shutdown(); |
1180 | 0 | // There is a case that RenderThread exists when gfxVars::UseWebRender() is false. |
1181 | 0 | // This could happen when WebRender was fallbacked to compositor. |
1182 | 0 | if (wr::RenderThread::Get()) { |
1183 | 0 | wr::RenderThread::ShutDown(); |
1184 | 0 |
|
1185 | 0 | Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF); |
1186 | 0 | } |
1187 | 0 |
|
1188 | 0 | } else { |
1189 | 0 | // TODO: There are other kind of processes and we should make sure gfx |
1190 | 0 | // stuff is either not created there or shut down properly. |
1191 | 0 | } |
1192 | 0 | } |
1193 | | |
1194 | | void |
1195 | | gfxPlatform::WillShutdown() |
1196 | 0 | { |
1197 | 0 | // Destoy these first in case they depend on backend-specific resources. |
1198 | 0 | // Otherwise, the backend's destructor would be called before the |
1199 | 0 | // base gfxPlatform destructor. |
1200 | 0 | mScreenReferenceSurface = nullptr; |
1201 | 0 | mScreenReferenceDrawTarget = nullptr; |
1202 | 0 | } |
1203 | | |
1204 | | gfxPlatform::~gfxPlatform() |
1205 | 0 | { |
1206 | 0 | // The cairo folks think we should only clean up in debug builds, |
1207 | 0 | // but we're generally in the habit of trying to shut down as |
1208 | 0 | // cleanly as possible even in production code, so call this |
1209 | 0 | // cairo_debug_* function unconditionally. |
1210 | 0 | // |
1211 | 0 | // because cairo can assert and thus crash on shutdown, don't do this in release builds |
1212 | | #ifdef NS_FREE_PERMANENT_DATA |
1213 | | #ifdef USE_SKIA |
1214 | | // must do Skia cleanup before Cairo cleanup, because Skia may be referencing |
1215 | | // Cairo objects e.g. through SkCairoFTTypeface |
1216 | | SkGraphics::PurgeFontCache(); |
1217 | | #endif |
1218 | | |
1219 | | #if MOZ_TREE_CAIRO |
1220 | | cairo_debug_reset_static_data(); |
1221 | | #endif |
1222 | | #endif |
1223 | | } |
1224 | | |
1225 | | /* static */ already_AddRefed<DrawTarget> |
1226 | | gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aSize) |
1227 | 0 | { |
1228 | 0 | SurfaceFormat format = aSurface->GetSurfaceFormat(); |
1229 | 0 | RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format); |
1230 | 0 | if (!drawTarget) { |
1231 | 0 | gfxWarning() << "gfxPlatform::CreateDrawTargetForSurface failed in CreateDrawTargetForCairoSurface"; |
1232 | 0 | return nullptr; |
1233 | 0 | } |
1234 | 0 | return drawTarget.forget(); |
1235 | 0 | } |
1236 | | |
1237 | | cairo_user_data_key_t kSourceSurface; |
1238 | | |
1239 | | /** |
1240 | | * Record the backend that was used to construct the SourceSurface. |
1241 | | * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair, |
1242 | | * we check to make sure the DrawTarget's backend matches the backend |
1243 | | * for the cached SourceSurface, and only use it if they match. This |
1244 | | * can avoid expensive and unnecessary readbacks. |
1245 | | */ |
1246 | | struct SourceSurfaceUserData |
1247 | | { |
1248 | | RefPtr<SourceSurface> mSrcSurface; |
1249 | | BackendType mBackendType; |
1250 | | }; |
1251 | | |
1252 | | void SourceBufferDestroy(void *srcSurfUD) |
1253 | 0 | { |
1254 | 0 | delete static_cast<SourceSurfaceUserData*>(srcSurfUD); |
1255 | 0 | } |
1256 | | |
1257 | | UserDataKey kThebesSurface; |
1258 | | |
1259 | | struct DependentSourceSurfaceUserData |
1260 | | { |
1261 | | RefPtr<gfxASurface> mSurface; |
1262 | | }; |
1263 | | |
1264 | | void SourceSurfaceDestroyed(void *aData) |
1265 | 0 | { |
1266 | 0 | delete static_cast<DependentSourceSurfaceUserData*>(aData); |
1267 | 0 | } |
1268 | | |
1269 | | void |
1270 | | gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface) |
1271 | 0 | { |
1272 | 0 | aSurface->SetData(&kSourceSurface, nullptr, nullptr); |
1273 | 0 | } |
1274 | | |
1275 | | /* static */ already_AddRefed<SourceSurface> |
1276 | | gfxPlatform::GetSourceSurfaceForSurface(RefPtr<DrawTarget> aTarget, |
1277 | | gfxASurface* aSurface, |
1278 | | bool aIsPlugin) |
1279 | 0 | { |
1280 | 0 | if (!aSurface->CairoSurface() || aSurface->CairoStatus()) { |
1281 | 0 | return nullptr; |
1282 | 0 | } |
1283 | 0 | |
1284 | 0 | if (!aTarget) { |
1285 | 0 | aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); |
1286 | 0 | } |
1287 | 0 |
|
1288 | 0 | void *userData = aSurface->GetData(&kSourceSurface); |
1289 | 0 |
|
1290 | 0 | if (userData) { |
1291 | 0 | SourceSurfaceUserData *surf = static_cast<SourceSurfaceUserData*>(userData); |
1292 | 0 |
|
1293 | 0 | if (surf->mSrcSurface->IsValid() && surf->mBackendType == aTarget->GetBackendType()) { |
1294 | 0 | RefPtr<SourceSurface> srcSurface(surf->mSrcSurface); |
1295 | 0 | return srcSurface.forget(); |
1296 | 0 | } |
1297 | 0 | // We can just continue here as when setting new user data the destroy |
1298 | 0 | // function will be called for the old user data. |
1299 | 0 | } |
1300 | 0 | |
1301 | 0 | SurfaceFormat format = aSurface->GetSurfaceFormat(); |
1302 | 0 |
|
1303 | 0 | if (aTarget->GetBackendType() == BackendType::CAIRO) { |
1304 | 0 | // If we're going to be used with a CAIRO DrawTarget, then just create a |
1305 | 0 | // SourceSurfaceCairo since we don't know the underlying type of the CAIRO |
1306 | 0 | // DrawTarget and can't pick a better surface type. Doing this also avoids |
1307 | 0 | // readback of aSurface's surface into memory if, for example, aSurface |
1308 | 0 | // wraps an xlib cairo surface (which can be important to avoid a major |
1309 | 0 | // slowdown). |
1310 | 0 | // |
1311 | 0 | // We return here regardless of whether CreateSourceSurfaceFromNativeSurface |
1312 | 0 | // succeeds or not since we don't expect to be able to do any better below |
1313 | 0 | // if it fails. |
1314 | 0 | // |
1315 | 0 | // Note that the returned SourceSurfaceCairo holds a strong reference to |
1316 | 0 | // the cairo_surface_t* that it wraps, which essencially means it holds a |
1317 | 0 | // strong reference to aSurface since aSurface shares its |
1318 | 0 | // cairo_surface_t*'s reference count variable. As a result we can't cache |
1319 | 0 | // srcBuffer on aSurface (see below) since aSurface would then hold a |
1320 | 0 | // strong reference back to srcBuffer, creating a reference loop and a |
1321 | 0 | // memory leak. Not caching is fine since wrapping is cheap enough (no |
1322 | 0 | // copying) so we can just wrap again next time we're called. |
1323 | 0 | return Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(), |
1324 | 0 | aSurface->GetSize(), format); |
1325 | 0 | } |
1326 | 0 | |
1327 | 0 | RefPtr<SourceSurface> srcBuffer; |
1328 | 0 |
|
1329 | 0 | // Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface |
1330 | 0 |
|
1331 | 0 | if (!srcBuffer) { |
1332 | 0 | // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps |
1333 | 0 | // the same data, then optimize it for aTarget: |
1334 | 0 | RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface); |
1335 | 0 | if (surf) { |
1336 | 0 | srcBuffer = aIsPlugin ? aTarget->OptimizeSourceSurfaceForUnknownAlpha(surf) |
1337 | 0 | : aTarget->OptimizeSourceSurface(surf); |
1338 | 0 |
|
1339 | 0 | if (srcBuffer == surf) { |
1340 | 0 | // GetWrappedDataSourceSurface returns a SourceSurface that holds a |
1341 | 0 | // strong reference to aSurface since it wraps aSurface's data and |
1342 | 0 | // needs it to stay alive. As a result we can't cache srcBuffer on |
1343 | 0 | // aSurface (below) since aSurface would then hold a strong reference |
1344 | 0 | // back to srcBuffer, creating a reference loop and a memory leak. Not |
1345 | 0 | // caching is fine since wrapping is cheap enough (no copying) so we |
1346 | 0 | // can just wrap again next time we're called. |
1347 | 0 | // |
1348 | 0 | // Note that the check below doesn't catch this since srcBuffer will be a |
1349 | 0 | // SourceSurfaceRawData object (even if aSurface is not a gfxImageSurface |
1350 | 0 | // object), which is why we need this separate check. |
1351 | 0 | return srcBuffer.forget(); |
1352 | 0 | } |
1353 | 0 | } |
1354 | 0 | } |
1355 | 0 | |
1356 | 0 | if (!srcBuffer) { |
1357 | 0 | MOZ_ASSERT(aTarget->GetBackendType() != BackendType::CAIRO, |
1358 | 0 | "We already tried CreateSourceSurfaceFromNativeSurface with a " |
1359 | 0 | "DrawTargetCairo above"); |
1360 | 0 | // We've run out of performant options. We now try creating a SourceSurface |
1361 | 0 | // using a temporary DrawTargetCairo and then optimizing it to aTarget's |
1362 | 0 | // actual type. The CreateSourceSurfaceFromNativeSurface() call will |
1363 | 0 | // likely create a DataSourceSurface (possibly involving copying and/or |
1364 | 0 | // readback), and the OptimizeSourceSurface may well copy again and upload |
1365 | 0 | // to the GPU. So, while this code path is rarely hit, hitting it may be |
1366 | 0 | // very slow. |
1367 | 0 | srcBuffer = Factory::CreateSourceSurfaceForCairoSurface(aSurface->CairoSurface(), |
1368 | 0 | aSurface->GetSize(), format); |
1369 | 0 | if (srcBuffer) { |
1370 | 0 | srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer); |
1371 | 0 | } |
1372 | 0 | } |
1373 | 0 |
|
1374 | 0 | if (!srcBuffer) { |
1375 | 0 | return nullptr; |
1376 | 0 | } |
1377 | 0 | |
1378 | 0 | if ((srcBuffer->GetType() == SurfaceType::CAIRO && |
1379 | 0 | static_cast<SourceSurfaceCairo*>(srcBuffer.get())->GetSurface() == |
1380 | 0 | aSurface->CairoSurface()) || |
1381 | 0 | (srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE && |
1382 | 0 | static_cast<DataSourceSurfaceCairo*>(srcBuffer.get())->GetSurface() == |
1383 | 0 | aSurface->CairoSurface())) { |
1384 | 0 | // See the "Note that the returned SourceSurfaceCairo..." comment above. |
1385 | 0 | return srcBuffer.forget(); |
1386 | 0 | } |
1387 | 0 | |
1388 | 0 | // Add user data to aSurface so we can cache lookups in the future. |
1389 | 0 | auto *srcSurfUD = new SourceSurfaceUserData; |
1390 | 0 | srcSurfUD->mBackendType = aTarget->GetBackendType(); |
1391 | 0 | srcSurfUD->mSrcSurface = srcBuffer; |
1392 | 0 | aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy); |
1393 | 0 |
|
1394 | 0 | return srcBuffer.forget(); |
1395 | 0 | } |
1396 | | |
1397 | | already_AddRefed<DataSourceSurface> |
1398 | | gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface) |
1399 | 0 | { |
1400 | 0 | RefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface(); |
1401 | 0 | if (!image) { |
1402 | 0 | return nullptr; |
1403 | 0 | } |
1404 | 0 | RefPtr<DataSourceSurface> result = |
1405 | 0 | Factory::CreateWrappingDataSourceSurface(image->Data(), |
1406 | 0 | image->Stride(), |
1407 | 0 | image->GetSize(), |
1408 | 0 | ImageFormatToSurfaceFormat(image->Format())); |
1409 | 0 |
|
1410 | 0 | if (!result) { |
1411 | 0 | return nullptr; |
1412 | 0 | } |
1413 | 0 | |
1414 | 0 | // If we wrapped the underlying data of aSurface, then we need to add user data |
1415 | 0 | // to make sure aSurface stays alive until we are done with the data. |
1416 | 0 | auto *srcSurfUD = new DependentSourceSurfaceUserData; |
1417 | 0 | srcSurfUD->mSurface = aSurface; |
1418 | 0 | result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed); |
1419 | 0 |
|
1420 | 0 | return result.forget(); |
1421 | 0 | } |
1422 | | |
1423 | | void |
1424 | | gfxPlatform::ComputeTileSize() |
1425 | 0 | { |
1426 | 0 | // The tile size should be picked in the parent processes |
1427 | 0 | // and sent to the child processes over IPDL GetTileSize. |
1428 | 0 | if (!XRE_IsParentProcess()) { |
1429 | 0 | return; |
1430 | 0 | } |
1431 | 0 | |
1432 | 0 | int32_t w = gfxPrefs::LayersTileWidth(); |
1433 | 0 | int32_t h = gfxPrefs::LayersTileHeight(); |
1434 | 0 |
|
1435 | 0 | if (gfxPrefs::LayersTilesAdjust()) { |
1436 | 0 | gfx::IntSize screenSize = GetScreenSize(); |
1437 | 0 | if (screenSize.width > 0) { |
1438 | 0 | // Choose a size so that there are between 2 and 4 tiles per screen width. |
1439 | 0 | // FIXME: we should probably make sure this is within the max texture size, |
1440 | 0 | // but I think everything should at least support 1024 |
1441 | 0 | w = h = clamped(int32_t(RoundUpPow2(screenSize.width)) / 4, 256, 1024); |
1442 | 0 | } |
1443 | 0 | } |
1444 | 0 |
|
1445 | 0 | // Don't allow changing the tile size after we've set it. |
1446 | 0 | // Right now the code assumes that the tile size doesn't change. |
1447 | 0 | MOZ_ASSERT(gfxVars::TileSize().width == -1 && |
1448 | 0 | gfxVars::TileSize().height == -1); |
1449 | 0 |
|
1450 | 0 | gfxVars::SetTileSize(IntSize(w, h)); |
1451 | 0 | } |
1452 | | |
1453 | | void |
1454 | | gfxPlatform::PopulateScreenInfo() |
1455 | 0 | { |
1456 | 0 | nsCOMPtr<nsIScreenManager> manager = do_GetService("@mozilla.org/gfx/screenmanager;1"); |
1457 | 0 | MOZ_ASSERT(manager, "failed to get nsIScreenManager"); |
1458 | 0 |
|
1459 | 0 | nsCOMPtr<nsIScreen> screen; |
1460 | 0 | manager->GetPrimaryScreen(getter_AddRefs(screen)); |
1461 | 0 | if (!screen) { |
1462 | 0 | // This can happen in xpcshell, for instance |
1463 | 0 | return; |
1464 | 0 | } |
1465 | 0 | |
1466 | 0 | screen->GetColorDepth(&mScreenDepth); |
1467 | 0 | if (XRE_IsParentProcess()) { |
1468 | 0 | gfxVars::SetScreenDepth(mScreenDepth); |
1469 | 0 | } |
1470 | 0 |
|
1471 | 0 | int left, top; |
1472 | 0 | screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height); |
1473 | 0 | } |
1474 | | |
1475 | | bool |
1476 | | gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget) |
1477 | 0 | { |
1478 | 0 | if (!aTarget || !aTarget->IsValid()) { |
1479 | 0 | return false; |
1480 | 0 | } |
1481 | 0 | |
1482 | 0 | #ifdef USE_SKIA_GPU |
1483 | 0 | // Skia content rendering doesn't support GPU acceleration, so we can't |
1484 | 0 | // use the same backend if the current backend is accelerated. |
1485 | 0 | if ((aTarget->GetType() == DrawTargetType::HARDWARE_RASTER) |
1486 | 0 | && (aTarget->GetBackendType() == BackendType::SKIA)) |
1487 | 0 | { |
1488 | 0 | return false; |
1489 | 0 | } |
1490 | 0 | #endif |
1491 | 0 | |
1492 | 0 | return SupportsAzureContentForType(aTarget->GetBackendType()); |
1493 | 0 | } |
1494 | | |
1495 | | bool gfxPlatform::AllowOpenGLCanvas() |
1496 | 0 | { |
1497 | 0 | // For now, only allow Skia+OpenGL, unless it's blocked. |
1498 | 0 | // Allow acceleration on Skia if the preference is set, unless it's blocked |
1499 | 0 | // as long as we have the accelerated layers |
1500 | 0 |
|
1501 | 0 | // The compositor backend is only set correctly in the parent process, |
1502 | 0 | // so we let content process always assume correct compositor backend. |
1503 | 0 | // The callers have to do the right thing. |
1504 | 0 | bool correctBackend = !XRE_IsParentProcess() || |
1505 | 0 | ((mCompositorBackend == LayersBackend::LAYERS_OPENGL || |
1506 | 0 | mCompositorBackend == LayersBackend::LAYERS_WR) && |
1507 | 0 | (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA)); |
1508 | 0 |
|
1509 | 0 | if (gfxPrefs::CanvasAzureAccelerated() && correctBackend) { |
1510 | 0 | nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); |
1511 | 0 | int32_t status; |
1512 | 0 | nsCString discardFailureId; |
1513 | 0 | return !gfxInfo || |
1514 | 0 | (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION, |
1515 | 0 | discardFailureId, |
1516 | 0 | &status)) && |
1517 | 0 | status == nsIGfxInfo::FEATURE_STATUS_OK); |
1518 | 0 | } |
1519 | 0 | return false; |
1520 | 0 | } |
1521 | | |
1522 | | void |
1523 | | gfxPlatform::InitializeSkiaCacheLimits() |
1524 | 0 | { |
1525 | 0 | if (AllowOpenGLCanvas()) { |
1526 | 0 | #ifdef USE_SKIA_GPU |
1527 | 0 | bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache(); |
1528 | 0 | int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems(); |
1529 | 0 | uint64_t cacheSizeLimit = std::max(gfxPrefs::CanvasSkiaGLCacheSize(), (int32_t)0); |
1530 | 0 |
|
1531 | 0 | // Prefs are in megabytes, but we want the sizes in bytes |
1532 | 0 | cacheSizeLimit *= 1024*1024; |
1533 | 0 |
|
1534 | 0 | if (usingDynamicCache) { |
1535 | 0 | if (mTotalSystemMemory < 512*1024*1024) { |
1536 | 0 | // We need a very minimal cache on anything smaller than 512mb. |
1537 | 0 | // Note the large jump as we cross 512mb (from 2mb to 32mb). |
1538 | 0 | cacheSizeLimit = 2*1024*1024; |
1539 | 0 | } else if (mTotalSystemMemory > 0) { |
1540 | 0 | cacheSizeLimit = mTotalSystemMemory / 16; |
1541 | 0 | } |
1542 | 0 | } |
1543 | 0 |
|
1544 | 0 | // Ensure cache size doesn't overflow on 32-bit platforms. |
1545 | 0 | cacheSizeLimit = std::min(cacheSizeLimit, (uint64_t)SIZE_MAX); |
1546 | 0 |
|
1547 | | #ifdef DEBUG |
1548 | | printf_stderr("Determined SkiaGL cache limits: Size %" PRIu64 ", Items: %i\n", cacheSizeLimit, cacheItemLimit); |
1549 | | #endif |
1550 | |
|
1551 | 0 | mSkiaGlue->GetGrContext()->setResourceCacheLimits(cacheItemLimit, (size_t)cacheSizeLimit); |
1552 | 0 | #endif |
1553 | 0 | } |
1554 | 0 | } |
1555 | | |
1556 | | SkiaGLGlue* |
1557 | | gfxPlatform::GetSkiaGLGlue() |
1558 | 0 | { |
1559 | 0 | #ifdef USE_SKIA_GPU |
1560 | 0 | // Check the accelerated Canvas is enabled for the first time, |
1561 | 0 | // because the callers should check it before using. |
1562 | 0 | if (!mSkiaGlue && !AllowOpenGLCanvas()) { |
1563 | 0 | return nullptr; |
1564 | 0 | } |
1565 | 0 | |
1566 | 0 | if (!mSkiaGlue) { |
1567 | 0 | /* Dummy context. We always draw into a FBO. |
1568 | 0 | * |
1569 | 0 | * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it |
1570 | 0 | * stands, this only works on the main thread. |
1571 | 0 | */ |
1572 | 0 | RefPtr<GLContext> glContext; |
1573 | 0 | nsCString discardFailureId; |
1574 | 0 | glContext = GLContextProvider::CreateHeadless(CreateContextFlags::REQUIRE_COMPAT_PROFILE | |
1575 | 0 | CreateContextFlags::ALLOW_OFFLINE_RENDERER, |
1576 | 0 | &discardFailureId); |
1577 | 0 | if (!glContext) { |
1578 | 0 | printf_stderr("Failed to create GLContext for SkiaGL!\n"); |
1579 | 0 | return nullptr; |
1580 | 0 | } |
1581 | 0 | mSkiaGlue = new SkiaGLGlue(glContext); |
1582 | 0 | MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext"); |
1583 | 0 | InitializeSkiaCacheLimits(); |
1584 | 0 | } |
1585 | 0 | #endif |
1586 | 0 |
|
1587 | 0 | return mSkiaGlue; |
1588 | 0 | } |
1589 | | |
1590 | | void |
1591 | | gfxPlatform::PurgeSkiaFontCache() |
1592 | 0 | { |
1593 | 0 | #ifdef USE_SKIA |
1594 | 0 | if (gfxPlatform::GetPlatform()->GetDefaultContentBackend() == BackendType::SKIA) { |
1595 | 0 | SkGraphics::PurgeFontCache(); |
1596 | 0 | } |
1597 | 0 | #endif |
1598 | 0 | } |
1599 | | |
1600 | | void |
1601 | | gfxPlatform::PurgeSkiaGPUCache() |
1602 | 0 | { |
1603 | 0 | #ifdef USE_SKIA_GPU |
1604 | 0 | if (!mSkiaGlue) |
1605 | 0 | return; |
1606 | 0 | |
1607 | 0 | mSkiaGlue->GetGrContext()->freeGpuResources(); |
1608 | 0 | // GrContext::flush() doesn't call glFlush. Call it here. |
1609 | 0 | mSkiaGlue->GetGLContext()->MakeCurrent(); |
1610 | 0 | mSkiaGlue->GetGLContext()->fFlush(); |
1611 | 0 | #endif |
1612 | 0 | } |
1613 | | |
1614 | | bool |
1615 | | gfxPlatform::HasEnoughTotalSystemMemoryForSkiaGL() |
1616 | 0 | { |
1617 | 0 | return true; |
1618 | 0 | } |
1619 | | |
1620 | | already_AddRefed<DrawTarget> |
1621 | | gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) |
1622 | 0 | { |
1623 | 0 | // There is a bunch of knowledge in the gfxPlatform heirarchy about how to |
1624 | 0 | // create the best offscreen surface for the current system and situation. We |
1625 | 0 | // can easily take advantage of this for the Cairo backend, so that's what we |
1626 | 0 | // do. |
1627 | 0 | // mozilla::gfx::Factory can get away without having all this knowledge for |
1628 | 0 | // now, but this might need to change in the future (using |
1629 | 0 | // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all |
1630 | 0 | // backends). |
1631 | 0 | if (aBackend == BackendType::CAIRO) { |
1632 | 0 | RefPtr<gfxASurface> surf = CreateOffscreenSurface(aSize, SurfaceFormatToImageFormat(aFormat)); |
1633 | 0 | if (!surf || surf->CairoStatus()) { |
1634 | 0 | return nullptr; |
1635 | 0 | } |
1636 | 0 | return CreateDrawTargetForSurface(surf, aSize); |
1637 | 0 | } |
1638 | 0 | return Factory::CreateDrawTarget(aBackend, aSize, aFormat); |
1639 | 0 | } |
1640 | | |
1641 | | already_AddRefed<DrawTarget> |
1642 | | gfxPlatform::CreateOffscreenCanvasDrawTarget(const IntSize& aSize, SurfaceFormat aFormat) |
1643 | 0 | { |
1644 | 0 | NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend."); |
1645 | 0 | RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat); |
1646 | 0 | if (target || |
1647 | 0 | mFallbackCanvasBackend == BackendType::NONE) { |
1648 | 0 | return target.forget(); |
1649 | 0 | } |
1650 | 0 | |
1651 | | #ifdef XP_WIN |
1652 | | // On Windows, the fallback backend (Cairo) should use its image backend. |
1653 | | return Factory::CreateDrawTarget(mFallbackCanvasBackend, aSize, aFormat); |
1654 | | #else |
1655 | 0 | return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat); |
1656 | 0 | #endif |
1657 | 0 | } |
1658 | | |
1659 | | already_AddRefed<DrawTarget> |
1660 | | gfxPlatform::CreateOffscreenContentDrawTarget(const IntSize& aSize, |
1661 | | SurfaceFormat aFormat, |
1662 | | bool aFallback) |
1663 | 0 | { |
1664 | 0 | BackendType backend = (aFallback) ? mSoftwareBackend : mContentBackend; |
1665 | 0 | NS_ASSERTION(backend != BackendType::NONE, "No backend."); |
1666 | 0 | return CreateDrawTargetForBackend(backend, aSize, aFormat); |
1667 | 0 | } |
1668 | | |
1669 | | already_AddRefed<DrawTarget> |
1670 | | gfxPlatform::CreateSimilarSoftwareDrawTarget(DrawTarget* aDT, |
1671 | | const IntSize& aSize, |
1672 | | SurfaceFormat aFormat) |
1673 | 0 | { |
1674 | 0 | RefPtr<DrawTarget> dt; |
1675 | 0 |
|
1676 | 0 | if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) { |
1677 | 0 | dt = aDT->CreateSimilarDrawTarget(aSize, aFormat); |
1678 | 0 | } else { |
1679 | 0 | #ifdef USE_SKIA |
1680 | 0 | BackendType backendType = BackendType::SKIA; |
1681 | | #else |
1682 | | BackendType backendType = BackendType::CAIRO; |
1683 | | #endif |
1684 | | dt = Factory::CreateDrawTarget(backendType, aSize, aFormat); |
1685 | 0 | } |
1686 | 0 |
|
1687 | 0 | return dt.forget(); |
1688 | 0 | } |
1689 | | |
1690 | | /* static */ already_AddRefed<DrawTarget> |
1691 | | gfxPlatform::CreateDrawTargetForData(unsigned char* aData, |
1692 | | const IntSize& aSize, |
1693 | | int32_t aStride, |
1694 | | SurfaceFormat aFormat, |
1695 | | bool aUninitialized) |
1696 | 0 | { |
1697 | 0 | BackendType backendType = gfxVars::ContentBackend(); |
1698 | 0 | NS_ASSERTION(backendType != BackendType::NONE, "No backend."); |
1699 | 0 |
|
1700 | 0 | if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) { |
1701 | 0 | #ifdef USE_SKIA |
1702 | 0 | backendType = BackendType::SKIA; |
1703 | | #else |
1704 | | backendType = BackendType::CAIRO; |
1705 | | #endif |
1706 | | } |
1707 | 0 |
|
1708 | 0 | RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(backendType, |
1709 | 0 | aData, aSize, |
1710 | 0 | aStride, aFormat, |
1711 | 0 | aUninitialized); |
1712 | 0 |
|
1713 | 0 | return dt.forget(); |
1714 | 0 | } |
1715 | | |
1716 | | /* static */ BackendType |
1717 | | gfxPlatform::BackendTypeForName(const nsCString& aName) |
1718 | 0 | { |
1719 | 0 | if (aName.EqualsLiteral("cairo")) |
1720 | 0 | return BackendType::CAIRO; |
1721 | 0 | if (aName.EqualsLiteral("skia")) |
1722 | 0 | return BackendType::SKIA; |
1723 | 0 | if (aName.EqualsLiteral("direct2d")) |
1724 | 0 | return BackendType::DIRECT2D; |
1725 | 0 | if (aName.EqualsLiteral("direct2d1.1")) |
1726 | 0 | return BackendType::DIRECT2D1_1; |
1727 | 0 | return BackendType::NONE; |
1728 | 0 | } |
1729 | | |
1730 | | nsresult |
1731 | | gfxPlatform::GetFontList(nsAtom *aLangGroup, |
1732 | | const nsACString& aGenericFamily, |
1733 | | nsTArray<nsString>& aListOfFonts) |
1734 | 0 | { |
1735 | 0 | gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, |
1736 | 0 | aGenericFamily, |
1737 | 0 | aListOfFonts); |
1738 | 0 | return NS_OK; |
1739 | 0 | } |
1740 | | |
1741 | | nsresult |
1742 | | gfxPlatform::UpdateFontList() |
1743 | 0 | { |
1744 | 0 | gfxPlatformFontList::PlatformFontList()->UpdateFontList(); |
1745 | 0 | return NS_OK; |
1746 | 0 | } |
1747 | | |
1748 | | void |
1749 | | gfxPlatform::GetStandardFamilyName(const nsCString& aFontName, |
1750 | | nsACString& aFamilyName) |
1751 | 0 | { |
1752 | 0 | gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, |
1753 | 0 | aFamilyName); |
1754 | 0 | } |
1755 | | |
1756 | | nsAutoCString |
1757 | | gfxPlatform::GetDefaultFontName(const nsACString& aLangGroup, |
1758 | | const nsACString& aGenericFamily) |
1759 | 0 | { |
1760 | 0 | // To benefit from Return Value Optimization, all paths here must return |
1761 | 0 | // this one variable: |
1762 | 0 | nsAutoCString result; |
1763 | 0 |
|
1764 | 0 | gfxFontFamily* fontFamily = gfxPlatformFontList::PlatformFontList()-> |
1765 | 0 | GetDefaultFontFamily(aLangGroup, aGenericFamily); |
1766 | 0 | if (fontFamily) { |
1767 | 0 | fontFamily->LocalizedName(result); |
1768 | 0 | } // (else, leave 'result' empty) |
1769 | 0 |
|
1770 | 0 | return result; |
1771 | 0 | } |
1772 | | |
1773 | | bool |
1774 | | gfxPlatform::DownloadableFontsEnabled() |
1775 | 0 | { |
1776 | 0 | if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) { |
1777 | 0 | mAllowDownloadableFonts = |
1778 | 0 | Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false); |
1779 | 0 | } |
1780 | 0 |
|
1781 | 0 | return mAllowDownloadableFonts; |
1782 | 0 | } |
1783 | | |
1784 | | bool |
1785 | | gfxPlatform::UseCmapsDuringSystemFallback() |
1786 | 0 | { |
1787 | 0 | if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) { |
1788 | 0 | mFallbackUsesCmaps = |
1789 | 0 | Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false); |
1790 | 0 | } |
1791 | 0 |
|
1792 | 0 | return mFallbackUsesCmaps; |
1793 | 0 | } |
1794 | | |
1795 | | bool |
1796 | | gfxPlatform::OpenTypeSVGEnabled() |
1797 | 0 | { |
1798 | 0 | if (mOpenTypeSVGEnabled == UNINITIALIZED_VALUE) { |
1799 | 0 | mOpenTypeSVGEnabled = |
1800 | 0 | Preferences::GetBool(GFX_PREF_OPENTYPE_SVG, false); |
1801 | 0 | } |
1802 | 0 |
|
1803 | 0 | return mOpenTypeSVGEnabled > 0; |
1804 | 0 | } |
1805 | | |
1806 | | uint32_t |
1807 | | gfxPlatform::WordCacheCharLimit() |
1808 | 0 | { |
1809 | 0 | if (mWordCacheCharLimit == UNINITIALIZED_VALUE) { |
1810 | 0 | mWordCacheCharLimit = |
1811 | 0 | Preferences::GetInt(GFX_PREF_WORD_CACHE_CHARLIMIT, 32); |
1812 | 0 | if (mWordCacheCharLimit < 0) { |
1813 | 0 | mWordCacheCharLimit = 32; |
1814 | 0 | } |
1815 | 0 | } |
1816 | 0 |
|
1817 | 0 | return uint32_t(mWordCacheCharLimit); |
1818 | 0 | } |
1819 | | |
1820 | | uint32_t |
1821 | | gfxPlatform::WordCacheMaxEntries() |
1822 | 0 | { |
1823 | 0 | if (mWordCacheMaxEntries == UNINITIALIZED_VALUE) { |
1824 | 0 | mWordCacheMaxEntries = |
1825 | 0 | Preferences::GetInt(GFX_PREF_WORD_CACHE_MAXENTRIES, 10000); |
1826 | 0 | if (mWordCacheMaxEntries < 0) { |
1827 | 0 | mWordCacheMaxEntries = 10000; |
1828 | 0 | } |
1829 | 0 | } |
1830 | 0 |
|
1831 | 0 | return uint32_t(mWordCacheMaxEntries); |
1832 | 0 | } |
1833 | | |
1834 | | bool |
1835 | | gfxPlatform::UseGraphiteShaping() |
1836 | 0 | { |
1837 | 0 | if (mGraphiteShapingEnabled == UNINITIALIZED_VALUE) { |
1838 | 0 | mGraphiteShapingEnabled = |
1839 | 0 | Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false); |
1840 | 0 | } |
1841 | 0 |
|
1842 | 0 | return mGraphiteShapingEnabled; |
1843 | 0 | } |
1844 | | |
1845 | | bool |
1846 | | gfxPlatform::IsFontFormatSupported(uint32_t aFormatFlags) |
1847 | 0 | { |
1848 | 0 | // check for strange format flags |
1849 | 0 | MOZ_ASSERT(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED), |
1850 | 0 | "strange font format hint set"); |
1851 | 0 |
|
1852 | 0 | // accept "common" formats that we support on all platforms |
1853 | 0 | if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) { |
1854 | 0 | return true; |
1855 | 0 | } |
1856 | 0 | |
1857 | 0 | // reject all other formats, known and unknown |
1858 | 0 | if (aFormatFlags != 0) { |
1859 | 0 | return false; |
1860 | 0 | } |
1861 | 0 | |
1862 | 0 | // no format hint set, need to look at data |
1863 | 0 | return true; |
1864 | 0 | } |
1865 | | |
1866 | | gfxFontEntry* |
1867 | | gfxPlatform::LookupLocalFont(const nsACString& aFontName, |
1868 | | WeightRange aWeightForEntry, |
1869 | | StretchRange aStretchForEntry, |
1870 | | SlantStyleRange aStyleForEntry) |
1871 | 0 | { |
1872 | 0 | return gfxPlatformFontList::PlatformFontList()-> |
1873 | 0 | LookupLocalFont(aFontName, aWeightForEntry, aStretchForEntry, |
1874 | 0 | aStyleForEntry); |
1875 | 0 | } |
1876 | | |
1877 | | gfxFontEntry* |
1878 | | gfxPlatform::MakePlatformFont(const nsACString& aFontName, |
1879 | | WeightRange aWeightForEntry, |
1880 | | StretchRange aStretchForEntry, |
1881 | | SlantStyleRange aStyleForEntry, |
1882 | | const uint8_t* aFontData, |
1883 | | uint32_t aLength) |
1884 | 0 | { |
1885 | 0 | return gfxPlatformFontList::PlatformFontList()-> |
1886 | 0 | MakePlatformFont(aFontName, aWeightForEntry, aStretchForEntry, |
1887 | 0 | aStyleForEntry, aFontData, aLength); |
1888 | 0 | } |
1889 | | |
1890 | | mozilla::layers::DiagnosticTypes |
1891 | | gfxPlatform::GetLayerDiagnosticTypes() |
1892 | 0 | { |
1893 | 0 | mozilla::layers::DiagnosticTypes type = DiagnosticTypes::NO_DIAGNOSTIC; |
1894 | 0 | if (gfxPrefs::DrawLayerBorders()) { |
1895 | 0 | type |= mozilla::layers::DiagnosticTypes::LAYER_BORDERS; |
1896 | 0 | } |
1897 | 0 | if (gfxPrefs::DrawTileBorders()) { |
1898 | 0 | type |= mozilla::layers::DiagnosticTypes::TILE_BORDERS; |
1899 | 0 | } |
1900 | 0 | if (gfxPrefs::DrawBigImageBorders()) { |
1901 | 0 | type |= mozilla::layers::DiagnosticTypes::BIGIMAGE_BORDERS; |
1902 | 0 | } |
1903 | 0 | if (gfxPrefs::FlashLayerBorders()) { |
1904 | 0 | type |= mozilla::layers::DiagnosticTypes::FLASH_BORDERS; |
1905 | 0 | } |
1906 | 0 | return type; |
1907 | 0 | } |
1908 | | |
1909 | | BackendPrefsData |
1910 | | gfxPlatform::GetBackendPrefs() const |
1911 | 0 | { |
1912 | 0 | BackendPrefsData data; |
1913 | 0 |
|
1914 | 0 | data.mCanvasBitmask = BackendTypeBit(BackendType::CAIRO); |
1915 | 0 | data.mContentBitmask = BackendTypeBit(BackendType::CAIRO); |
1916 | 0 | #ifdef USE_SKIA |
1917 | 0 | data.mCanvasBitmask |= BackendTypeBit(BackendType::SKIA); |
1918 | 0 | data.mContentBitmask |= BackendTypeBit(BackendType::SKIA); |
1919 | 0 | #endif |
1920 | 0 | data.mCanvasDefault = BackendType::CAIRO; |
1921 | 0 | data.mContentDefault = BackendType::CAIRO; |
1922 | 0 |
|
1923 | 0 | return data; |
1924 | 0 | } |
1925 | | |
1926 | | void |
1927 | | gfxPlatform::InitBackendPrefs(BackendPrefsData&& aPrefsData) |
1928 | 0 | { |
1929 | 0 | mPreferredCanvasBackend = GetCanvasBackendPref(aPrefsData.mCanvasBitmask); |
1930 | 0 | if (mPreferredCanvasBackend == BackendType::NONE) { |
1931 | 0 | mPreferredCanvasBackend = aPrefsData.mCanvasDefault; |
1932 | 0 | } |
1933 | 0 |
|
1934 | 0 | if (mPreferredCanvasBackend == BackendType::DIRECT2D1_1) { |
1935 | 0 | // Falling back to D2D 1.0 won't help us here. When D2D 1.1 DT creation |
1936 | 0 | // fails it means the surface was too big or there's something wrong with |
1937 | 0 | // the device. D2D 1.0 will encounter a similar situation. |
1938 | 0 | mFallbackCanvasBackend = |
1939 | 0 | GetCanvasBackendPref(aPrefsData.mCanvasBitmask & |
1940 | 0 | ~(BackendTypeBit(mPreferredCanvasBackend) | BackendTypeBit(BackendType::DIRECT2D))); |
1941 | 0 | } else { |
1942 | 0 | mFallbackCanvasBackend = |
1943 | 0 | GetCanvasBackendPref(aPrefsData.mCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend)); |
1944 | 0 | } |
1945 | 0 |
|
1946 | 0 |
|
1947 | 0 | mContentBackendBitmask = aPrefsData.mContentBitmask; |
1948 | 0 | mContentBackend = GetContentBackendPref(mContentBackendBitmask); |
1949 | 0 | if (mContentBackend == BackendType::NONE) { |
1950 | 0 | mContentBackend = aPrefsData.mContentDefault; |
1951 | 0 | // mContentBackendBitmask is our canonical reference for supported |
1952 | 0 | // backends so we need to add the default if we are using it and |
1953 | 0 | // overriding the prefs. |
1954 | 0 | mContentBackendBitmask |= BackendTypeBit(aPrefsData.mContentDefault); |
1955 | 0 | } |
1956 | 0 |
|
1957 | 0 | uint32_t swBackendBits = BackendTypeBit(BackendType::SKIA) | |
1958 | 0 | BackendTypeBit(BackendType::CAIRO); |
1959 | 0 | mSoftwareBackend = GetContentBackendPref(swBackendBits); |
1960 | 0 |
|
1961 | 0 | if (XRE_IsParentProcess()) { |
1962 | 0 | gfxVars::SetContentBackend(mContentBackend); |
1963 | 0 | gfxVars::SetSoftwareBackend(mSoftwareBackend); |
1964 | 0 | } |
1965 | 0 | } |
1966 | | |
1967 | | /* static */ BackendType |
1968 | | gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask) |
1969 | 0 | { |
1970 | 0 | return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask); |
1971 | 0 | } |
1972 | | |
1973 | | /* static */ BackendType |
1974 | | gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask) |
1975 | 0 | { |
1976 | 0 | return GetBackendPref("gfx.content.azure.backends", aBackendBitmask); |
1977 | 0 | } |
1978 | | |
1979 | | /* static */ BackendType |
1980 | | gfxPlatform::GetBackendPref(const char* aBackendPrefName, uint32_t &aBackendBitmask) |
1981 | 0 | { |
1982 | 0 | nsTArray<nsCString> backendList; |
1983 | 0 | nsAutoCString prefString; |
1984 | 0 | if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, prefString))) { |
1985 | 0 | ParseString(prefString, ',', backendList); |
1986 | 0 | } |
1987 | 0 |
|
1988 | 0 | uint32_t allowedBackends = 0; |
1989 | 0 | BackendType result = BackendType::NONE; |
1990 | 0 | for (uint32_t i = 0; i < backendList.Length(); ++i) { |
1991 | 0 | BackendType type = BackendTypeForName(backendList[i]); |
1992 | 0 | if (BackendTypeBit(type) & aBackendBitmask) { |
1993 | 0 | allowedBackends |= BackendTypeBit(type); |
1994 | 0 | if (result == BackendType::NONE) { |
1995 | 0 | result = type; |
1996 | 0 | } |
1997 | 0 | } |
1998 | 0 | } |
1999 | 0 |
|
2000 | 0 | aBackendBitmask = allowedBackends; |
2001 | 0 | return result; |
2002 | 0 | } |
2003 | | |
2004 | | bool |
2005 | | gfxPlatform::InSafeMode() |
2006 | 0 | { |
2007 | 0 | static bool sSafeModeInitialized = false; |
2008 | 0 | static bool sInSafeMode = false; |
2009 | 0 |
|
2010 | 0 | if (!sSafeModeInitialized) { |
2011 | 0 | sSafeModeInitialized = true; |
2012 | 0 | nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1"); |
2013 | 0 | if (xr) { |
2014 | 0 | xr->GetInSafeMode(&sInSafeMode); |
2015 | 0 | } |
2016 | 0 | } |
2017 | 0 | return sInSafeMode; |
2018 | 0 | } |
2019 | | |
2020 | | bool |
2021 | | gfxPlatform::OffMainThreadCompositingEnabled() |
2022 | 0 | { |
2023 | 0 | return UsesOffMainThreadCompositing(); |
2024 | 0 | } |
2025 | | |
2026 | | eCMSMode |
2027 | | gfxPlatform::GetCMSMode() |
2028 | 0 | { |
2029 | 0 | if (!gCMSInitialized) { |
2030 | 0 | int32_t mode = gfxPrefs::CMSMode(); |
2031 | 0 | if (mode >= 0 && mode < eCMSMode_AllCount) { |
2032 | 0 | gCMSMode = static_cast<eCMSMode>(mode); |
2033 | 0 | } |
2034 | 0 |
|
2035 | 0 | bool enableV4 = gfxPrefs::CMSEnableV4(); |
2036 | 0 | if (enableV4) { |
2037 | 0 | qcms_enable_iccv4(); |
2038 | 0 | } |
2039 | 0 | gCMSInitialized = true; |
2040 | 0 | } |
2041 | 0 | return gCMSMode; |
2042 | 0 | } |
2043 | | |
2044 | | int |
2045 | | gfxPlatform::GetRenderingIntent() |
2046 | 0 | { |
2047 | 0 | // gfxPrefs.h is using 0 as the default for the rendering |
2048 | 0 | // intent preference, based on that being the value for |
2049 | 0 | // QCMS_INTENT_DEFAULT. Assert here to catch if that ever |
2050 | 0 | // changes and we can then figure out what to do about it. |
2051 | 0 | MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0); |
2052 | 0 |
|
2053 | 0 | /* Try to query the pref system for a rendering intent. */ |
2054 | 0 | int32_t pIntent = gfxPrefs::CMSRenderingIntent(); |
2055 | 0 | if ((pIntent < QCMS_INTENT_MIN) || (pIntent > QCMS_INTENT_MAX)) { |
2056 | 0 | /* If the pref is out of range, use embedded profile. */ |
2057 | 0 | pIntent = -1; |
2058 | 0 | } |
2059 | 0 | return pIntent; |
2060 | 0 | } |
2061 | | |
2062 | | void |
2063 | | gfxPlatform::TransformPixel(const Color& in, Color& out, qcms_transform *transform) |
2064 | 0 | { |
2065 | 0 |
|
2066 | 0 | if (transform) { |
2067 | 0 | /* we want the bytes in RGB order */ |
2068 | 0 | #ifdef IS_LITTLE_ENDIAN |
2069 | 0 | /* ABGR puts the bytes in |RGBA| order on little endian */ |
2070 | 0 | uint32_t packed = in.ToABGR(); |
2071 | 0 | qcms_transform_data(transform, |
2072 | 0 | (uint8_t *)&packed, (uint8_t *)&packed, |
2073 | 0 | 1); |
2074 | 0 | out = Color::FromABGR(packed); |
2075 | | #else |
2076 | | /* ARGB puts the bytes in |ARGB| order on big endian */ |
2077 | | uint32_t packed = in.UnusualToARGB(); |
2078 | | /* add one to move past the alpha byte */ |
2079 | | qcms_transform_data(transform, |
2080 | | (uint8_t *)&packed + 1, (uint8_t *)&packed + 1, |
2081 | | 1); |
2082 | | out = Color::UnusualFromARGB(packed); |
2083 | | #endif |
2084 | | } |
2085 | 0 |
|
2086 | 0 | else if (&out != &in) |
2087 | 0 | out = in; |
2088 | 0 | } |
2089 | | |
2090 | | void |
2091 | | gfxPlatform::GetPlatformCMSOutputProfile(void *&mem, size_t &size) |
2092 | 0 | { |
2093 | 0 | mem = nullptr; |
2094 | 0 | size = 0; |
2095 | 0 | } |
2096 | | |
2097 | | void |
2098 | | gfxPlatform::GetCMSOutputProfileData(void *&mem, size_t &size) |
2099 | 0 | { |
2100 | 0 | nsAutoCString fname; |
2101 | 0 | Preferences::GetCString("gfx.color_management.display_profile", fname); |
2102 | 0 | if (!fname.IsEmpty()) { |
2103 | 0 | qcms_data_from_path(fname.get(), &mem, &size); |
2104 | 0 | } |
2105 | 0 | else { |
2106 | 0 | gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfile(mem, size); |
2107 | 0 | } |
2108 | 0 | } |
2109 | | |
2110 | | void |
2111 | | gfxPlatform::CreateCMSOutputProfile() |
2112 | 0 | { |
2113 | 0 | if (!gCMSOutputProfile) { |
2114 | 0 | /* Determine if we're using the internal override to force sRGB as |
2115 | 0 | an output profile for reftests. See Bug 452125. |
2116 | 0 |
|
2117 | 0 | Note that we don't normally (outside of tests) set a |
2118 | 0 | default value of this preference, which means nsIPrefBranch::GetBoolPref |
2119 | 0 | will typically throw (and leave its out-param untouched). |
2120 | 0 | */ |
2121 | 0 | if (Preferences::GetBool(GFX_PREF_CMS_FORCE_SRGB, false)) { |
2122 | 0 | gCMSOutputProfile = GetCMSsRGBProfile(); |
2123 | 0 | } |
2124 | 0 |
|
2125 | 0 | if (!gCMSOutputProfile) { |
2126 | 0 | void* mem = nullptr; |
2127 | 0 | size_t size = 0; |
2128 | 0 |
|
2129 | 0 | GetCMSOutputProfileData(mem, size); |
2130 | 0 | if ((mem != nullptr) && (size > 0)) { |
2131 | 0 | gCMSOutputProfile = qcms_profile_from_memory(mem, size); |
2132 | 0 | free(mem); |
2133 | 0 | } |
2134 | 0 | } |
2135 | 0 |
|
2136 | 0 | /* Determine if the profile looks bogus. If so, close the profile |
2137 | 0 | * and use sRGB instead. See bug 460629, */ |
2138 | 0 | if (gCMSOutputProfile && qcms_profile_is_bogus(gCMSOutputProfile)) { |
2139 | 0 | NS_ASSERTION(gCMSOutputProfile != GetCMSsRGBProfile(), |
2140 | 0 | "Builtin sRGB profile tagged as bogus!!!"); |
2141 | 0 | qcms_profile_release(gCMSOutputProfile); |
2142 | 0 | gCMSOutputProfile = nullptr; |
2143 | 0 | } |
2144 | 0 |
|
2145 | 0 | if (!gCMSOutputProfile) { |
2146 | 0 | gCMSOutputProfile = GetCMSsRGBProfile(); |
2147 | 0 | } |
2148 | 0 | /* Precache the LUT16 Interpolations for the output profile. See |
2149 | 0 | bug 444661 for details. */ |
2150 | 0 | qcms_profile_precache_output_transform(gCMSOutputProfile); |
2151 | 0 | } |
2152 | 0 | } |
2153 | | |
2154 | | qcms_profile * |
2155 | | gfxPlatform::GetCMSOutputProfile() |
2156 | 0 | { |
2157 | 0 | return gCMSOutputProfile; |
2158 | 0 | } |
2159 | | |
2160 | | qcms_profile * |
2161 | | gfxPlatform::GetCMSsRGBProfile() |
2162 | 0 | { |
2163 | 0 | if (!gCMSsRGBProfile) { |
2164 | 0 |
|
2165 | 0 | /* Create the profile using qcms. */ |
2166 | 0 | gCMSsRGBProfile = qcms_profile_sRGB(); |
2167 | 0 | } |
2168 | 0 | return gCMSsRGBProfile; |
2169 | 0 | } |
2170 | | |
2171 | | qcms_transform * |
2172 | | gfxPlatform::GetCMSRGBTransform() |
2173 | 0 | { |
2174 | 0 | if (!gCMSRGBTransform && !gCMSRGBTransformFailed) { |
2175 | 0 | qcms_profile *inProfile, *outProfile; |
2176 | 0 | outProfile = GetCMSOutputProfile(); |
2177 | 0 | inProfile = GetCMSsRGBProfile(); |
2178 | 0 |
|
2179 | 0 | if (!inProfile || !outProfile) |
2180 | 0 | return nullptr; |
2181 | 0 | |
2182 | 0 | gCMSRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8, |
2183 | 0 | outProfile, QCMS_DATA_RGB_8, |
2184 | 0 | QCMS_INTENT_PERCEPTUAL); |
2185 | 0 | if (!gCMSRGBTransform) { |
2186 | 0 | gCMSRGBTransformFailed = true; |
2187 | 0 | } |
2188 | 0 | } |
2189 | 0 |
|
2190 | 0 | return gCMSRGBTransform; |
2191 | 0 | } |
2192 | | |
2193 | | qcms_transform * |
2194 | | gfxPlatform::GetCMSInverseRGBTransform() |
2195 | 0 | { |
2196 | 0 | if (!gCMSInverseRGBTransform) { |
2197 | 0 | qcms_profile *inProfile, *outProfile; |
2198 | 0 | inProfile = GetCMSOutputProfile(); |
2199 | 0 | outProfile = GetCMSsRGBProfile(); |
2200 | 0 |
|
2201 | 0 | if (!inProfile || !outProfile) |
2202 | 0 | return nullptr; |
2203 | 0 | |
2204 | 0 | gCMSInverseRGBTransform = qcms_transform_create(inProfile, QCMS_DATA_RGB_8, |
2205 | 0 | outProfile, QCMS_DATA_RGB_8, |
2206 | 0 | QCMS_INTENT_PERCEPTUAL); |
2207 | 0 | } |
2208 | 0 |
|
2209 | 0 | return gCMSInverseRGBTransform; |
2210 | 0 | } |
2211 | | |
2212 | | qcms_transform * |
2213 | | gfxPlatform::GetCMSRGBATransform() |
2214 | 0 | { |
2215 | 0 | if (!gCMSRGBATransform) { |
2216 | 0 | qcms_profile *inProfile, *outProfile; |
2217 | 0 | outProfile = GetCMSOutputProfile(); |
2218 | 0 | inProfile = GetCMSsRGBProfile(); |
2219 | 0 |
|
2220 | 0 | if (!inProfile || !outProfile) |
2221 | 0 | return nullptr; |
2222 | 0 | |
2223 | 0 | gCMSRGBATransform = qcms_transform_create(inProfile, QCMS_DATA_RGBA_8, |
2224 | 0 | outProfile, QCMS_DATA_RGBA_8, |
2225 | 0 | QCMS_INTENT_PERCEPTUAL); |
2226 | 0 | } |
2227 | 0 |
|
2228 | 0 | return gCMSRGBATransform; |
2229 | 0 | } |
2230 | | |
2231 | | /* Shuts down various transforms and profiles for CMS. */ |
2232 | | static void ShutdownCMS() |
2233 | 0 | { |
2234 | 0 |
|
2235 | 0 | if (gCMSRGBTransform) { |
2236 | 0 | qcms_transform_release(gCMSRGBTransform); |
2237 | 0 | gCMSRGBTransform = nullptr; |
2238 | 0 | } |
2239 | 0 | if (gCMSInverseRGBTransform) { |
2240 | 0 | qcms_transform_release(gCMSInverseRGBTransform); |
2241 | 0 | gCMSInverseRGBTransform = nullptr; |
2242 | 0 | } |
2243 | 0 | if (gCMSRGBATransform) { |
2244 | 0 | qcms_transform_release(gCMSRGBATransform); |
2245 | 0 | gCMSRGBATransform = nullptr; |
2246 | 0 | } |
2247 | 0 | if (gCMSOutputProfile) { |
2248 | 0 | qcms_profile_release(gCMSOutputProfile); |
2249 | 0 |
|
2250 | 0 | // handle the aliased case |
2251 | 0 | if (gCMSsRGBProfile == gCMSOutputProfile) |
2252 | 0 | gCMSsRGBProfile = nullptr; |
2253 | 0 | gCMSOutputProfile = nullptr; |
2254 | 0 | } |
2255 | 0 | if (gCMSsRGBProfile) { |
2256 | 0 | qcms_profile_release(gCMSsRGBProfile); |
2257 | 0 | gCMSsRGBProfile = nullptr; |
2258 | 0 | } |
2259 | 0 |
|
2260 | 0 | // Reset the state variables |
2261 | 0 | gCMSMode = eCMSMode_Off; |
2262 | 0 | gCMSInitialized = false; |
2263 | 0 | } |
2264 | | |
2265 | | // default SetupClusterBoundaries, based on Unicode properties; |
2266 | | // platform subclasses may override if they wish |
2267 | | void |
2268 | | gfxPlatform::SetupClusterBoundaries(gfxTextRun *aTextRun, const char16_t *aString) |
2269 | 0 | { |
2270 | 0 | if (aTextRun->GetFlags() & gfx::ShapedTextFlags::TEXT_IS_8BIT) { |
2271 | 0 | // 8-bit text doesn't have clusters. |
2272 | 0 | // XXX is this true in all languages??? |
2273 | 0 | // behdad: don't think so. Czech for example IIRC has a |
2274 | 0 | // 'ch' grapheme. |
2275 | 0 | // jfkthame: but that's not expected to behave as a grapheme cluster |
2276 | 0 | // for selection/editing/etc. |
2277 | 0 | return; |
2278 | 0 | } |
2279 | 0 | |
2280 | 0 | aTextRun->SetupClusterBoundaries(0, aString, aTextRun->GetLength()); |
2281 | 0 | } |
2282 | | |
2283 | | int32_t |
2284 | | gfxPlatform::GetBidiNumeralOption() |
2285 | 0 | { |
2286 | 0 | if (mBidiNumeralOption == UNINITIALIZED_VALUE) { |
2287 | 0 | mBidiNumeralOption = Preferences::GetInt(BIDI_NUMERAL_PREF, 0); |
2288 | 0 | } |
2289 | 0 | return mBidiNumeralOption; |
2290 | 0 | } |
2291 | | |
2292 | | /* static */ void |
2293 | | gfxPlatform::FlushFontAndWordCaches() |
2294 | 0 | { |
2295 | 0 | gfxFontCache *fontCache = gfxFontCache::GetCache(); |
2296 | 0 | if (fontCache) { |
2297 | 0 | fontCache->AgeAllGenerations(); |
2298 | 0 | fontCache->FlushShapedWordCaches(); |
2299 | 0 | } |
2300 | 0 |
|
2301 | 0 | gfxPlatform::PurgeSkiaFontCache(); |
2302 | 0 | } |
2303 | | |
2304 | | /* static */ void |
2305 | | gfxPlatform::ForceGlobalReflow() |
2306 | 0 | { |
2307 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
2308 | 0 | if (XRE_IsParentProcess()) { |
2309 | 0 | // Modify a preference that will trigger reflow everywhere (in all |
2310 | 0 | // content processes, as well as the parent). |
2311 | 0 | static const char kPrefName[] = "font.internaluseonly.changed"; |
2312 | 0 | bool fontInternalChange = Preferences::GetBool(kPrefName, false); |
2313 | 0 | Preferences::SetBool(kPrefName, !fontInternalChange); |
2314 | 0 | } else { |
2315 | 0 | // Send a notification that will be observed by PresShells in this |
2316 | 0 | // process only. |
2317 | 0 | nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); |
2318 | 0 | if (obs) { |
2319 | 0 | obs->NotifyObservers(nullptr, "font-info-updated", nullptr); |
2320 | 0 | } |
2321 | 0 | } |
2322 | 0 | } |
2323 | | |
2324 | | void |
2325 | | gfxPlatform::FontsPrefsChanged(const char *aPref) |
2326 | 0 | { |
2327 | 0 | NS_ASSERTION(aPref != nullptr, "null preference"); |
2328 | 0 | if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) { |
2329 | 0 | mAllowDownloadableFonts = UNINITIALIZED_VALUE; |
2330 | 0 | } else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) { |
2331 | 0 | mFallbackUsesCmaps = UNINITIALIZED_VALUE; |
2332 | 0 | } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref)) { |
2333 | 0 | mWordCacheCharLimit = UNINITIALIZED_VALUE; |
2334 | 0 | FlushFontAndWordCaches(); |
2335 | 0 | } else if (!strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref)) { |
2336 | 0 | mWordCacheMaxEntries = UNINITIALIZED_VALUE; |
2337 | 0 | FlushFontAndWordCaches(); |
2338 | 0 | } else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) { |
2339 | 0 | mGraphiteShapingEnabled = UNINITIALIZED_VALUE; |
2340 | 0 | FlushFontAndWordCaches(); |
2341 | 0 | } else if (!strcmp(BIDI_NUMERAL_PREF, aPref)) { |
2342 | 0 | mBidiNumeralOption = UNINITIALIZED_VALUE; |
2343 | 0 | } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) { |
2344 | 0 | mOpenTypeSVGEnabled = UNINITIALIZED_VALUE; |
2345 | 0 | gfxFontCache::GetCache()->AgeAllGenerations(); |
2346 | 0 | gfxFontCache::GetCache()->NotifyGlyphsChanged(); |
2347 | 0 | } |
2348 | 0 | } |
2349 | | |
2350 | | |
2351 | | mozilla::LogModule* |
2352 | | gfxPlatform::GetLog(eGfxLog aWhichLog) |
2353 | 0 | { |
2354 | 0 | // logs shared across gfx |
2355 | 0 | static LazyLogModule sFontlistLog("fontlist"); |
2356 | 0 | static LazyLogModule sFontInitLog("fontinit"); |
2357 | 0 | static LazyLogModule sTextrunLog("textrun"); |
2358 | 0 | static LazyLogModule sTextrunuiLog("textrunui"); |
2359 | 0 | static LazyLogModule sCmapDataLog("cmapdata"); |
2360 | 0 | static LazyLogModule sTextPerfLog("textperf"); |
2361 | 0 |
|
2362 | 0 | switch (aWhichLog) { |
2363 | 0 | case eGfxLog_fontlist: |
2364 | 0 | return sFontlistLog; |
2365 | 0 | case eGfxLog_fontinit: |
2366 | 0 | return sFontInitLog; |
2367 | 0 | case eGfxLog_textrun: |
2368 | 0 | return sTextrunLog; |
2369 | 0 | case eGfxLog_textrunui: |
2370 | 0 | return sTextrunuiLog; |
2371 | 0 | case eGfxLog_cmapdata: |
2372 | 0 | return sCmapDataLog; |
2373 | 0 | case eGfxLog_textperf: |
2374 | 0 | return sTextPerfLog; |
2375 | 0 | } |
2376 | 0 | |
2377 | 0 | MOZ_ASSERT_UNREACHABLE("Unexpected log type"); |
2378 | 0 | return nullptr; |
2379 | 0 | } |
2380 | | |
2381 | | RefPtr<mozilla::gfx::DrawTarget> |
2382 | | gfxPlatform::ScreenReferenceDrawTarget() |
2383 | 0 | { |
2384 | 0 | return (mScreenReferenceDrawTarget) |
2385 | 0 | ? mScreenReferenceDrawTarget |
2386 | 0 | : gPlatform->CreateOffscreenContentDrawTarget( |
2387 | 0 | IntSize(1, 1), SurfaceFormat::B8G8R8A8, true); |
2388 | 0 | } |
2389 | | |
2390 | | mozilla::gfx::SurfaceFormat |
2391 | | gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent) |
2392 | 0 | { |
2393 | 0 | switch (aContent) { |
2394 | 0 | case gfxContentType::COLOR: |
2395 | 0 | switch (GetOffscreenFormat()) { |
2396 | 0 | case SurfaceFormat::A8R8G8B8_UINT32: |
2397 | 0 | return mozilla::gfx::SurfaceFormat::B8G8R8A8; |
2398 | 0 | case SurfaceFormat::X8R8G8B8_UINT32: |
2399 | 0 | return mozilla::gfx::SurfaceFormat::B8G8R8X8; |
2400 | 0 | case SurfaceFormat::R5G6B5_UINT16: |
2401 | 0 | return mozilla::gfx::SurfaceFormat::R5G6B5_UINT16; |
2402 | 0 | default: |
2403 | 0 | MOZ_ASSERT_UNREACHABLE("unknown gfxImageFormat for " |
2404 | 0 | "gfxContentType::COLOR"); |
2405 | 0 | return mozilla::gfx::SurfaceFormat::B8G8R8A8; |
2406 | 0 | } |
2407 | 0 | case gfxContentType::ALPHA: |
2408 | 0 | return mozilla::gfx::SurfaceFormat::A8; |
2409 | 0 | case gfxContentType::COLOR_ALPHA: |
2410 | 0 | return mozilla::gfx::SurfaceFormat::B8G8R8A8; |
2411 | 0 | default: |
2412 | 0 | MOZ_ASSERT_UNREACHABLE("unknown gfxContentType"); |
2413 | 0 | return mozilla::gfx::SurfaceFormat::B8G8R8A8; |
2414 | 0 | } |
2415 | 0 | } |
2416 | | |
2417 | | gfxImageFormat |
2418 | | gfxPlatform::OptimalFormatForContent(gfxContentType aContent) |
2419 | 0 | { |
2420 | 0 | switch (aContent) { |
2421 | 0 | case gfxContentType::COLOR: |
2422 | 0 | return GetOffscreenFormat(); |
2423 | 0 | case gfxContentType::ALPHA: |
2424 | 0 | return SurfaceFormat::A8; |
2425 | 0 | case gfxContentType::COLOR_ALPHA: |
2426 | 0 | return SurfaceFormat::A8R8G8B8_UINT32; |
2427 | 0 | default: |
2428 | 0 | MOZ_ASSERT_UNREACHABLE("unknown gfxContentType"); |
2429 | 0 | return SurfaceFormat::A8R8G8B8_UINT32; |
2430 | 0 | } |
2431 | 0 | } |
2432 | | |
2433 | | /** |
2434 | | * There are a number of layers acceleration (or layers in general) preferences |
2435 | | * that should be consistent for the lifetime of the application (bug 840967). |
2436 | | * As such, we will evaluate them all as soon as one of them is evaluated |
2437 | | * and remember the values. Changing these preferences during the run will |
2438 | | * not have any effect until we restart. |
2439 | | */ |
2440 | | static mozilla::Atomic<bool> sLayersSupportsHardwareVideoDecoding(false); |
2441 | | static bool sLayersHardwareVideoDecodingFailed = false; |
2442 | | static bool sBufferRotationCheckPref = true; |
2443 | | |
2444 | | static mozilla::Atomic<bool> sLayersAccelerationPrefsInitialized(false); |
2445 | | |
2446 | | void VideoDecodingFailedChangedCallback(const char* aPref, void*) |
2447 | 0 | { |
2448 | 0 | sLayersHardwareVideoDecodingFailed = Preferences::GetBool(aPref, false); |
2449 | 0 | gfxPlatform::GetPlatform()->UpdateCanUseHardwareVideoDecoding(); |
2450 | 0 | } |
2451 | | |
2452 | | void |
2453 | | gfxPlatform::UpdateCanUseHardwareVideoDecoding() |
2454 | 0 | { |
2455 | 0 | if (XRE_IsParentProcess()) { |
2456 | 0 | gfxVars::SetCanUseHardwareVideoDecoding(CanUseHardwareVideoDecoding()); |
2457 | 0 | } |
2458 | 0 | } |
2459 | | |
2460 | | void |
2461 | | gfxPlatform::InitAcceleration() |
2462 | 0 | { |
2463 | 0 | if (sLayersAccelerationPrefsInitialized) { |
2464 | 0 | return; |
2465 | 0 | } |
2466 | 0 | |
2467 | 0 | InitCompositorAccelerationPrefs(); |
2468 | 0 |
|
2469 | 0 | // If this is called for the first time on a non-main thread, we're screwed. |
2470 | 0 | // At the moment there's no explicit guarantee that the main thread calls |
2471 | 0 | // this before the compositor thread, but let's at least make the assumption |
2472 | 0 | // explicit. |
2473 | 0 | MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread"); |
2474 | 0 |
|
2475 | 0 | gfxPrefs::GetSingleton(); |
2476 | 0 |
|
2477 | 0 | nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); |
2478 | 0 | nsCString discardFailureId; |
2479 | 0 | int32_t status; |
2480 | 0 |
|
2481 | 0 | if (XRE_IsParentProcess()) { |
2482 | 0 | gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart()); |
2483 | 0 | gfxVars::SetOffscreenFormat(GetOffscreenFormat()); |
2484 | 0 | gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL( |
2485 | 0 | RequiresAcceleratedGLContextForCompositorOGL()); |
2486 | | #ifdef XP_WIN |
2487 | | if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX, |
2488 | | discardFailureId, &status))) { |
2489 | | gfxVars::SetAllowD3D11KeyedMutex(status == nsIGfxInfo::FEATURE_STATUS_OK); |
2490 | | } else { |
2491 | | // If we couldn't properly evaluate the status, err on the side |
2492 | | // of caution and give this functionality to the user. |
2493 | | gfxCriticalNote << "Cannot evaluate keyed mutex feature status"; |
2494 | | gfxVars::SetAllowD3D11KeyedMutex(true); |
2495 | | } |
2496 | | #endif |
2497 | | } |
2498 | 0 |
|
2499 | 0 | if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) && |
2500 | | #ifdef XP_WIN |
2501 | | Preferences::GetBool("media.wmf.dxva.enabled", true) && |
2502 | | #endif |
2503 | 0 | NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, |
2504 | 0 | discardFailureId, &status))) { |
2505 | 0 | if (status == nsIGfxInfo::FEATURE_STATUS_OK || gfxPrefs::HardwareVideoDecodingForceEnabled()) { |
2506 | 0 | sLayersSupportsHardwareVideoDecoding = true; |
2507 | 0 | } |
2508 | 0 | } |
2509 | 0 |
|
2510 | 0 | sLayersAccelerationPrefsInitialized = true; |
2511 | 0 |
|
2512 | 0 | if (XRE_IsParentProcess()) { |
2513 | 0 | Preferences::RegisterCallbackAndCall(VideoDecodingFailedChangedCallback, |
2514 | 0 | "media.hardware-video-decoding.failed"); |
2515 | 0 | InitGPUProcessPrefs(); |
2516 | 0 | } |
2517 | 0 | } |
2518 | | |
2519 | | void |
2520 | | gfxPlatform::InitGPUProcessPrefs() |
2521 | 0 | { |
2522 | 0 | // We want to hide this from about:support, so only set a default if the |
2523 | 0 | // pref is known to be true. |
2524 | 0 | if (!gfxPrefs::GPUProcessEnabled() && !gfxPrefs::GPUProcessForceEnabled()) { |
2525 | 0 | return; |
2526 | 0 | } |
2527 | 0 | |
2528 | 0 | FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS); |
2529 | 0 |
|
2530 | 0 | // We require E10S - otherwise, there is very little benefit to the GPU |
2531 | 0 | // process, since the UI process must still use acceleration for |
2532 | 0 | // performance. |
2533 | 0 | if (!BrowserTabsRemoteAutostart()) { |
2534 | 0 | gpuProc.DisableByDefault( |
2535 | 0 | FeatureStatus::Unavailable, |
2536 | 0 | "Multi-process mode is not enabled", |
2537 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_E10S")); |
2538 | 0 | } else { |
2539 | 0 | gpuProc.SetDefaultFromPref( |
2540 | 0 | gfxPrefs::GetGPUProcessEnabledPrefName(), |
2541 | 0 | true, |
2542 | 0 | gfxPrefs::GetGPUProcessEnabledPrefDefault()); |
2543 | 0 | } |
2544 | 0 |
|
2545 | 0 | if (gfxPrefs::GPUProcessForceEnabled()) { |
2546 | 0 | gpuProc.UserForceEnable("User force-enabled via pref"); |
2547 | 0 | } |
2548 | 0 |
|
2549 | 0 | if (IsHeadless()) { |
2550 | 0 | gpuProc.ForceDisable( |
2551 | 0 | FeatureStatus::Blocked, |
2552 | 0 | "Headless mode is enabled", |
2553 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_HEADLESS_MODE")); |
2554 | 0 | return; |
2555 | 0 | } |
2556 | 0 | if (InSafeMode()) { |
2557 | 0 | gpuProc.ForceDisable( |
2558 | 0 | FeatureStatus::Blocked, |
2559 | 0 | "Safe-mode is enabled", |
2560 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE")); |
2561 | 0 | return; |
2562 | 0 | } |
2563 | 0 | if (gfxPrefs::LayerScopeEnabled()) { |
2564 | 0 | gpuProc.ForceDisable( |
2565 | 0 | FeatureStatus::Blocked, |
2566 | 0 | "LayerScope does not work in the GPU process", |
2567 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_LAYERSCOPE")); |
2568 | 0 | return; |
2569 | 0 | } |
2570 | 0 | } |
2571 | | |
2572 | | void |
2573 | | gfxPlatform::InitCompositorAccelerationPrefs() |
2574 | 0 | { |
2575 | 0 | const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED"); |
2576 | 0 |
|
2577 | 0 | FeatureState& feature = gfxConfig::GetFeature(Feature::HW_COMPOSITING); |
2578 | 0 |
|
2579 | 0 | // Base value - does the platform allow acceleration? |
2580 | 0 | if (feature.SetDefault(AccelerateLayersByDefault(), |
2581 | 0 | FeatureStatus::Blocked, |
2582 | 0 | "Acceleration blocked by platform")) |
2583 | 0 | { |
2584 | 0 | if (gfxPrefs::LayersAccelerationDisabledDoNotUseDirectly()) { |
2585 | 0 | feature.UserDisable("Disabled by pref", |
2586 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF")); |
2587 | 0 | } else if (acceleratedEnv && *acceleratedEnv == '0') { |
2588 | 0 | feature.UserDisable("Disabled by envvar", |
2589 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_ENV")); |
2590 | 0 | } |
2591 | 0 | } else { |
2592 | 0 | if (acceleratedEnv && *acceleratedEnv == '1') { |
2593 | 0 | feature.UserEnable("Enabled by envvar"); |
2594 | 0 | } |
2595 | 0 | } |
2596 | 0 |
|
2597 | 0 | // This has specific meaning elsewhere, so we always record it. |
2598 | 0 | if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) { |
2599 | 0 | feature.UserForceEnable("Force-enabled by pref"); |
2600 | 0 | } |
2601 | 0 |
|
2602 | 0 | // Safe, headless, and record/replay modes override everything. |
2603 | 0 | if (InSafeMode()) { |
2604 | 0 | feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by safe-mode", |
2605 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE")); |
2606 | 0 | } |
2607 | 0 | if (IsHeadless()) { |
2608 | 0 | feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by headless mode", |
2609 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_HEADLESSMODE")); |
2610 | 0 | } |
2611 | 0 | if (recordreplay::IsRecordingOrReplaying()) { |
2612 | 0 | feature.ForceDisable(FeatureStatus::Blocked, "Acceleration blocked by recording/replaying", |
2613 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_RECORDREPLAY")); |
2614 | 0 | } |
2615 | 0 | } |
2616 | | |
2617 | | /*static*/ bool |
2618 | | gfxPlatform::WebRenderPrefEnabled() |
2619 | 0 | { |
2620 | 0 | return gfxPrefs::WebRenderAll() || gfxPrefs::WebRenderEnabledDoNotUseDirectly(); |
2621 | 0 | } |
2622 | | |
2623 | | /*static*/ bool |
2624 | | gfxPlatform::WebRenderEnvvarEnabled() |
2625 | 0 | { |
2626 | 0 | const char* env = PR_GetEnv("MOZ_WEBRENDER"); |
2627 | 0 | return (env && *env == '1'); |
2628 | 0 | } |
2629 | | |
2630 | | /* This is a pretty conservative check for having a battery. |
2631 | | * For now we'd rather err on the side of thinking we do. */ |
2632 | | static bool HasBattery() |
2633 | 0 | { |
2634 | | #ifdef XP_WIN |
2635 | | SYSTEM_POWER_STATUS status; |
2636 | | const BYTE NO_SYSTEM_BATTERY = 128; |
2637 | | if (GetSystemPowerStatus(&status)) { |
2638 | | if (status.BatteryFlag == NO_SYSTEM_BATTERY) { |
2639 | | return false; |
2640 | | } |
2641 | | } |
2642 | | #endif |
2643 | | return true; |
2644 | 0 | } |
2645 | | |
2646 | | void |
2647 | | gfxPlatform::InitWebRenderConfig() |
2648 | 0 | { |
2649 | 0 | bool prefEnabled = WebRenderPrefEnabled(); |
2650 | 0 | bool envvarEnabled = WebRenderEnvvarEnabled(); |
2651 | 0 |
|
2652 | 0 | // On Nightly: |
2653 | 0 | // WR? WR+ => means WR was enabled via gfx.webrender.all.qualified |
2654 | 0 | // WR! WR+ => means WR was enabled via gfx.webrender.{all,enabled} or envvar |
2655 | 0 | // On Beta/Release: |
2656 | 0 | // WR? WR+ => means WR was enabled via gfx.webrender.all.qualified on qualified hardware |
2657 | 0 | // WR! WR+ => means WR was enabled via envvar, possibly on unqualified hardware. |
2658 | 0 | // In all cases WR- means WR was not enabled, for one of many possible reasons. |
2659 | 0 | ScopedGfxFeatureReporter reporter("WR", prefEnabled || envvarEnabled); |
2660 | 0 | if (!XRE_IsParentProcess()) { |
2661 | 0 | // The parent process runs through all the real decision-making code |
2662 | 0 | // later in this function. For other processes we still want to report |
2663 | 0 | // the state of the feature for crash reports. |
2664 | 0 | if (gfxVars::UseWebRender()) { |
2665 | 0 | reporter.SetSuccessful(); |
2666 | 0 | } |
2667 | 0 | return; |
2668 | 0 | } |
2669 | 0 |
|
2670 | 0 | FeatureState& featureWebRenderQualified = gfxConfig::GetFeature(Feature::WEBRENDER_QUALIFIED); |
2671 | 0 | featureWebRenderQualified.EnableByDefault(); |
2672 | 0 | nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); |
2673 | 0 | nsCString failureId; |
2674 | 0 | int32_t status; |
2675 | 0 | if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRENDER, |
2676 | 0 | failureId, &status))) { |
2677 | 0 | if (status != nsIGfxInfo::FEATURE_STATUS_OK) { |
2678 | 0 | featureWebRenderQualified.Disable(FeatureStatus::Blocked, |
2679 | 0 | "No qualified hardware", |
2680 | 0 | failureId); |
2681 | 0 | } else if (HasBattery()) { |
2682 | 0 | featureWebRenderQualified.Disable(FeatureStatus::Blocked, |
2683 | 0 | "Has battery", |
2684 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_WR_HAS_BATTERY")); |
2685 | 0 | } else { |
2686 | 0 | nsAutoString adapterVendorID; |
2687 | 0 | gfxInfo->GetAdapterVendorID(adapterVendorID); |
2688 | 0 | if (adapterVendorID != u"0x10de") { |
2689 | 0 | featureWebRenderQualified.Disable(FeatureStatus::Blocked, |
2690 | 0 | "Not Nvidia", |
2691 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_NOT_NVIDIA")); |
2692 | 0 | } else { |
2693 | 0 | nsAutoString adapterDeviceID; |
2694 | 0 | gfxInfo->GetAdapterDeviceID(adapterDeviceID); |
2695 | 0 | nsresult valid; |
2696 | 0 | int32_t deviceID = adapterDeviceID.ToInteger(&valid, 16); |
2697 | 0 | if (valid != NS_OK) { |
2698 | 0 | featureWebRenderQualified.Disable(FeatureStatus::Blocked, |
2699 | 0 | "Bad device id", |
2700 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_BAD_DEVICE_ID")); |
2701 | 0 | } else if (deviceID < 0x6c0) { |
2702 | 0 | // 0x6c0 is the lowest Fermi device id. Unfortunately some Tesla devices that don't support D3D 10.1 |
2703 | 0 | // have higher deviceIDs. They will be included, but blocked by ANGLE. |
2704 | 0 | featureWebRenderQualified.Disable(FeatureStatus::Blocked, |
2705 | 0 | "Device too old", |
2706 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_DEVICE_TOO_OLD")); |
2707 | 0 | } |
2708 | 0 | } |
2709 | 0 | } |
2710 | 0 | } else { |
2711 | 0 | featureWebRenderQualified.Disable(FeatureStatus::Blocked, |
2712 | 0 | "gfxInfo is broken", |
2713 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_WR_NO_GFX_INFO")); |
2714 | 0 | } |
2715 | 0 |
|
2716 | 0 | FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER); |
2717 | 0 |
|
2718 | 0 | featureWebRender.DisableByDefault( |
2719 | 0 | FeatureStatus::OptIn, |
2720 | 0 | "WebRender is an opt-in feature", |
2721 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF")); |
2722 | 0 |
|
2723 | 0 | // envvar works everywhere; we need this for testing in CI. Sadly this allows |
2724 | 0 | // beta/release to enable it on unqualified hardware, but at least this is |
2725 | 0 | // harder for the average person than flipping a pref. |
2726 | 0 | if (envvarEnabled) { |
2727 | 0 | featureWebRender.UserEnable("Force enabled by envvar"); |
2728 | 0 |
|
2729 | 0 | // gfx.webrender.enabled and gfx.webrender.all only work on nightly |
2730 | 0 | #ifdef NIGHTLY_BUILD |
2731 | 0 | } else if (prefEnabled) { |
2732 | 0 | featureWebRender.UserEnable("Force enabled by pref"); |
2733 | 0 | #endif |
2734 | 0 |
|
2735 | 0 | // gfx.webrender.all.qualified works on all channels |
2736 | 0 | } else if (gfxPrefs::WebRenderAllQualified()) { |
2737 | 0 | if (featureWebRenderQualified.IsEnabled()) { |
2738 | 0 | featureWebRender.UserEnable("Qualified enabled by pref "); |
2739 | 0 | } else { |
2740 | 0 | featureWebRender.ForceDisable(FeatureStatus::Blocked, |
2741 | 0 | "Qualified enable blocked", |
2742 | 0 | failureId); |
2743 | 0 | } |
2744 | 0 | } |
2745 | 0 |
|
2746 | 0 | // If the user set the pref to force-disable, let's do that. This will |
2747 | 0 | // override all the other enabling prefs (gfx.webrender.enabled, |
2748 | 0 | // gfx.webrender.all, and gfx.webrender.all.qualified). |
2749 | 0 | if (gfxPrefs::WebRenderForceDisabled()) { |
2750 | 0 | featureWebRender.UserDisable( |
2751 | 0 | "User force-disabled WR", |
2752 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_USER_FORCE_DISABLED")); |
2753 | 0 | } |
2754 | 0 |
|
2755 | 0 | // HW_COMPOSITING being disabled implies interfacing with the GPU might break |
2756 | 0 | if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) { |
2757 | 0 | featureWebRender.ForceDisable( |
2758 | 0 | FeatureStatus::Unavailable, |
2759 | 0 | "Hardware compositing is disabled", |
2760 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_NEED_HWCOMP")); |
2761 | 0 | } |
2762 | 0 |
|
2763 | 0 | // WebRender relies on the GPU process when on Windows |
2764 | | #ifdef XP_WIN |
2765 | | if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { |
2766 | | featureWebRender.ForceDisable( |
2767 | | FeatureStatus::Unavailable, |
2768 | | "GPU Process is disabled", |
2769 | | NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED")); |
2770 | | } |
2771 | | #endif |
2772 | |
|
2773 | 0 | if (InSafeMode()) { |
2774 | 0 | featureWebRender.ForceDisable( |
2775 | 0 | FeatureStatus::Unavailable, |
2776 | 0 | "Safe-mode is enabled", |
2777 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE")); |
2778 | 0 | } |
2779 | 0 |
|
2780 | | #ifndef MOZ_BUILD_WEBRENDER |
2781 | | featureWebRender.ForceDisable( |
2782 | | FeatureStatus::Unavailable, |
2783 | | "Build doesn't include WebRender", |
2784 | | NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_WEBRENDER")); |
2785 | | #endif |
2786 | |
|
2787 | | #ifdef XP_WIN |
2788 | | if (Preferences::GetBool("gfx.webrender.force-angle", false)) { |
2789 | | if (!gfxConfig::IsEnabled(Feature::D3D11_HW_ANGLE)) { |
2790 | | featureWebRender.ForceDisable( |
2791 | | FeatureStatus::Unavailable, |
2792 | | "ANGLE is disabled", |
2793 | | NS_LITERAL_CSTRING("FEATURE_FAILURE_ANGLE_DISABLED")); |
2794 | | } else { |
2795 | | gfxVars::SetUseWebRenderANGLE(gfxConfig::IsEnabled(Feature::WEBRENDER)); |
2796 | | } |
2797 | | } |
2798 | | #endif |
2799 | |
|
2800 | 0 | if (Preferences::GetBool("gfx.webrender.program-binary", false)) { |
2801 | 0 | gfxVars::SetUseWebRenderProgramBinary(gfxConfig::IsEnabled(Feature::WEBRENDER)); |
2802 | 0 | if (Preferences::GetBool("gfx.webrender.program-binary-disk", false)) { |
2803 | 0 | gfxVars::SetUseWebRenderProgramBinaryDisk(gfxConfig::IsEnabled(Feature::WEBRENDER)); |
2804 | 0 | } |
2805 | 0 | } |
2806 | 0 |
|
2807 | | #ifdef MOZ_WIDGET_ANDROID |
2808 | | featureWebRender.ForceDisable( |
2809 | | FeatureStatus::Unavailable, |
2810 | | "WebRender not ready for use on Android", |
2811 | | NS_LITERAL_CSTRING("FEATURE_FAILURE_ANDROID")); |
2812 | | #endif |
2813 | |
|
2814 | 0 | // gfxFeature is not usable in the GPU process, so we use gfxVars to transmit this feature |
2815 | 0 | if (gfxConfig::IsEnabled(Feature::WEBRENDER)) { |
2816 | 0 | gfxVars::SetUseWebRender(true); |
2817 | 0 | reporter.SetSuccessful(); |
2818 | 0 |
|
2819 | 0 | if (XRE_IsParentProcess()) { |
2820 | 0 | Preferences::RegisterPrefixCallbackAndCall(WebRenderDebugPrefChangeCallback, |
2821 | 0 | WR_DEBUG_PREF); |
2822 | 0 | } |
2823 | 0 | } |
2824 | 0 |
|
2825 | | #ifdef XP_WIN |
2826 | | if (Preferences::GetBool("gfx.webrender.dcomp-win.enabled", false)) { |
2827 | | // XXX relax win version to windows 8. |
2828 | | if (IsWin10OrLater() && |
2829 | | gfxVars::UseWebRender() && |
2830 | | gfxVars::UseWebRenderANGLE()) { |
2831 | | gfxVars::SetUseWebRenderDCompWin(true); |
2832 | | } |
2833 | | } |
2834 | | #endif |
2835 | | } |
2836 | | |
2837 | | void |
2838 | | gfxPlatform::InitOMTPConfig() |
2839 | 0 | { |
2840 | 0 | ScopedGfxFeatureReporter reporter("OMTP"); |
2841 | 0 |
|
2842 | 0 | FeatureState& omtp = gfxConfig::GetFeature(Feature::OMTP); |
2843 | 0 | int32_t paintWorkerCount = PaintThread::CalculatePaintWorkerCount(); |
2844 | 0 |
|
2845 | 0 | if (!XRE_IsParentProcess()) { |
2846 | 0 | // The parent process runs through all the real decision-making code |
2847 | 0 | // later in this function. For other processes we still want to report |
2848 | 0 | // the state of the feature for crash reports. |
2849 | 0 | if (gfxVars::UseOMTP()) { |
2850 | 0 | reporter.SetSuccessful(paintWorkerCount); |
2851 | 0 | } |
2852 | 0 | return; |
2853 | 0 | } |
2854 | 0 |
|
2855 | 0 | omtp.SetDefaultFromPref( |
2856 | 0 | "layers.omtp.enabled", |
2857 | 0 | true, |
2858 | 0 | Preferences::GetBool("layers.omtp.enabled", false, PrefValueKind::Default)); |
2859 | 0 |
|
2860 | 0 | if (mContentBackend == BackendType::CAIRO) { |
2861 | 0 | omtp.ForceDisable(FeatureStatus::Broken, "OMTP is not supported when using cairo", |
2862 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_PREF")); |
2863 | 0 | } |
2864 | 0 |
|
2865 | | #ifdef XP_MACOSX |
2866 | | if (!nsCocoaFeatures::OnYosemiteOrLater()) { |
2867 | | omtp.ForceDisable(FeatureStatus::Blocked, "OMTP blocked before OSX 10.10", |
2868 | | NS_LITERAL_CSTRING("FEATURE_FAILURE_OMTP_OSX_MAVERICKS")); |
2869 | | } |
2870 | | #endif |
2871 | |
|
2872 | 0 | if (InSafeMode()) { |
2873 | 0 | omtp.ForceDisable(FeatureStatus::Blocked, "OMTP blocked by safe-mode", |
2874 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_COMP_SAFEMODE")); |
2875 | 0 | } |
2876 | 0 |
|
2877 | 0 | if (omtp.IsEnabled()) { |
2878 | 0 | gfxVars::SetUseOMTP(true); |
2879 | 0 | reporter.SetSuccessful(paintWorkerCount); |
2880 | 0 | } |
2881 | 0 | } |
2882 | | |
2883 | | bool |
2884 | | gfxPlatform::CanUseHardwareVideoDecoding() |
2885 | 0 | { |
2886 | 0 | // this function is called from the compositor thread, so it is not |
2887 | 0 | // safe to init the prefs etc. from here. |
2888 | 0 | MOZ_ASSERT(sLayersAccelerationPrefsInitialized); |
2889 | 0 | return sLayersSupportsHardwareVideoDecoding && !sLayersHardwareVideoDecodingFailed; |
2890 | 0 | } |
2891 | | |
2892 | | bool |
2893 | | gfxPlatform::AccelerateLayersByDefault() |
2894 | 0 | { |
2895 | | #if defined(MOZ_GL_PROVIDER) || defined(MOZ_WIDGET_UIKIT) |
2896 | | return true; |
2897 | | #else |
2898 | | return false; |
2899 | 0 | #endif |
2900 | 0 | } |
2901 | | |
2902 | | bool |
2903 | | gfxPlatform::BufferRotationEnabled() |
2904 | 0 | { |
2905 | 0 | MutexAutoLock autoLock(*gGfxPlatformPrefsLock); |
2906 | 0 |
|
2907 | 0 | return sBufferRotationCheckPref && gfxPrefs::BufferRotationEnabled(); |
2908 | 0 | } |
2909 | | |
2910 | | void |
2911 | | gfxPlatform::DisableBufferRotation() |
2912 | 0 | { |
2913 | 0 | MutexAutoLock autoLock(*gGfxPlatformPrefsLock); |
2914 | 0 |
|
2915 | 0 | sBufferRotationCheckPref = false; |
2916 | 0 | } |
2917 | | |
2918 | | /* static */ bool |
2919 | | gfxPlatform::UsesOffMainThreadCompositing() |
2920 | 0 | { |
2921 | 0 | if (XRE_GetProcessType() == GeckoProcessType_GPU) { |
2922 | 0 | return true; |
2923 | 0 | } |
2924 | 0 | |
2925 | 0 | static bool firstTime = true; |
2926 | 0 | static bool result = false; |
2927 | 0 |
|
2928 | 0 | if (firstTime) { |
2929 | 0 | MOZ_ASSERT(sLayersAccelerationPrefsInitialized); |
2930 | 0 | result = |
2931 | 0 | gfxVars::BrowserTabsRemoteAutostart() || |
2932 | 0 | !gfxPrefs::LayersOffMainThreadCompositionForceDisabled(); |
2933 | 0 | #if defined(MOZ_WIDGET_GTK) |
2934 | 0 | // Linux users who chose OpenGL are being grandfathered in to OMTC |
2935 | 0 | result |= gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly(); |
2936 | 0 |
|
2937 | 0 | #endif |
2938 | 0 | firstTime = false; |
2939 | 0 | } |
2940 | 0 |
|
2941 | 0 | return result; |
2942 | 0 | } |
2943 | | |
2944 | | bool |
2945 | | gfxPlatform::UsesTiling() const |
2946 | 0 | { |
2947 | 0 | bool usesSkia = GetDefaultContentBackend() == BackendType::SKIA; |
2948 | 0 |
|
2949 | 0 | // We can't just test whether the PaintThread is initialized here because |
2950 | 0 | // this function is used when initializing the PaintThread. So instead we |
2951 | 0 | // check the conditions that enable OMTP with parallel painting. |
2952 | 0 | bool usesPOMTP = XRE_IsContentProcess() && |
2953 | 0 | gfxVars::UseOMTP() && |
2954 | 0 | (gfxPrefs::LayersOMTPPaintWorkers() == -1 || |
2955 | 0 | gfxPrefs::LayersOMTPPaintWorkers() > 1); |
2956 | 0 |
|
2957 | 0 | return gfxPrefs::LayersTilesEnabled() || |
2958 | 0 | (gfxPrefs::LayersTilesEnabledIfSkiaPOMTP() && |
2959 | 0 | usesSkia && |
2960 | 0 | usesPOMTP); |
2961 | 0 | } |
2962 | | |
2963 | | bool |
2964 | | gfxPlatform::ContentUsesTiling() const |
2965 | 0 | { |
2966 | 0 | BackendPrefsData data = GetBackendPrefs(); |
2967 | 0 | BackendType contentBackend = GetContentBackendPref(data.mContentBitmask); |
2968 | 0 | if (contentBackend == BackendType::NONE) { |
2969 | 0 | contentBackend = data.mContentDefault; |
2970 | 0 | } |
2971 | 0 |
|
2972 | 0 | bool contentUsesSkia = contentBackend == BackendType::SKIA; |
2973 | 0 | bool contentUsesPOMTP = gfxVars::UseOMTP() && |
2974 | 0 | (gfxPrefs::LayersOMTPPaintWorkers() == -1 || |
2975 | 0 | gfxPrefs::LayersOMTPPaintWorkers() > 1); |
2976 | 0 |
|
2977 | 0 | return gfxPrefs::LayersTilesEnabled() || |
2978 | 0 | (gfxPrefs::LayersTilesEnabledIfSkiaPOMTP() && |
2979 | 0 | contentUsesSkia && |
2980 | 0 | contentUsesPOMTP); |
2981 | 0 | } |
2982 | | |
2983 | | /*** |
2984 | | * The preference "layout.frame_rate" has 3 meanings depending on the value: |
2985 | | * |
2986 | | * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw vsync fails. |
2987 | | * 0 = ASAP mode - used during talos testing. |
2988 | | * X = Software vsync at a rate of X times per second. |
2989 | | */ |
2990 | | already_AddRefed<mozilla::gfx::VsyncSource> |
2991 | | gfxPlatform::CreateHardwareVsyncSource() |
2992 | 0 | { |
2993 | 0 | RefPtr<mozilla::gfx::VsyncSource> softwareVsync = new SoftwareVsyncSource(); |
2994 | 0 | return softwareVsync.forget(); |
2995 | 0 | } |
2996 | | |
2997 | | /* static */ bool |
2998 | | gfxPlatform::IsInLayoutAsapMode() |
2999 | 0 | { |
3000 | 0 | // There are 2 modes of ASAP mode. |
3001 | 0 | // 1 is that the refresh driver and compositor are in lock step |
3002 | 0 | // the second is that the compositor goes ASAP and the refresh driver |
3003 | 0 | // goes at whatever the configurated rate is. This only checks the version |
3004 | 0 | // talos uses, which is the refresh driver and compositor are in lockstep. |
3005 | 0 | return gfxPrefs::LayoutFrameRate() == 0; |
3006 | 0 | } |
3007 | | |
3008 | | /* static */ bool |
3009 | | gfxPlatform::ForceSoftwareVsync() |
3010 | 0 | { |
3011 | 0 | return gfxPrefs::LayoutFrameRate() > 0 || recordreplay::IsRecordingOrReplaying(); |
3012 | 0 | } |
3013 | | |
3014 | | /* static */ int |
3015 | | gfxPlatform::GetSoftwareVsyncRate() |
3016 | 0 | { |
3017 | 0 | int preferenceRate = gfxPrefs::LayoutFrameRate(); |
3018 | 0 | if (preferenceRate <= 0) { |
3019 | 0 | return gfxPlatform::GetDefaultFrameRate(); |
3020 | 0 | } |
3021 | 0 | return preferenceRate; |
3022 | 0 | } |
3023 | | |
3024 | | /* static */ int |
3025 | | gfxPlatform::GetDefaultFrameRate() |
3026 | 0 | { |
3027 | 0 | return 60; |
3028 | 0 | } |
3029 | | |
3030 | | void |
3031 | | gfxPlatform::GetAzureBackendInfo(mozilla::widget::InfoObject& aObj) |
3032 | 0 | { |
3033 | 0 | if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { |
3034 | 0 | aObj.DefineProperty("AzureCanvasBackend (UI Process)", GetBackendName(mPreferredCanvasBackend)); |
3035 | 0 | aObj.DefineProperty("AzureFallbackCanvasBackend (UI Process)", GetBackendName(mFallbackCanvasBackend)); |
3036 | 0 | aObj.DefineProperty("AzureContentBackend (UI Process)", GetBackendName(mContentBackend)); |
3037 | 0 |
|
3038 | 0 | // Assume content process' backend prefs. |
3039 | 0 | BackendPrefsData data = GetBackendPrefs(); |
3040 | 0 | BackendType canvasBackend = GetCanvasBackendPref(data.mCanvasBitmask); |
3041 | 0 | if (canvasBackend == BackendType::NONE) { |
3042 | 0 | canvasBackend = data.mCanvasDefault; |
3043 | 0 | } |
3044 | 0 | BackendType contentBackend = GetContentBackendPref(data.mContentBitmask); |
3045 | 0 | if (contentBackend == BackendType::NONE) { |
3046 | 0 | contentBackend = data.mContentDefault; |
3047 | 0 | } |
3048 | 0 | aObj.DefineProperty("AzureCanvasBackend", GetBackendName(canvasBackend)); |
3049 | 0 | aObj.DefineProperty("AzureContentBackend", GetBackendName(contentBackend)); |
3050 | 0 | } else { |
3051 | 0 | aObj.DefineProperty("AzureCanvasBackend", GetBackendName(mPreferredCanvasBackend)); |
3052 | 0 | aObj.DefineProperty("AzureFallbackCanvasBackend", GetBackendName(mFallbackCanvasBackend)); |
3053 | 0 | aObj.DefineProperty("AzureContentBackend", GetBackendName(mContentBackend)); |
3054 | 0 | } |
3055 | 0 |
|
3056 | 0 | aObj.DefineProperty("AzureCanvasAccelerated", AllowOpenGLCanvas()); |
3057 | 0 | } |
3058 | | |
3059 | | void |
3060 | | gfxPlatform::GetApzSupportInfo(mozilla::widget::InfoObject& aObj) |
3061 | 0 | { |
3062 | 0 | if (!gfxPlatform::AsyncPanZoomEnabled()) { |
3063 | 0 | return; |
3064 | 0 | } |
3065 | 0 | |
3066 | 0 | if (SupportsApzWheelInput()) { |
3067 | 0 | aObj.DefineProperty("ApzWheelInput", 1); |
3068 | 0 | } |
3069 | 0 |
|
3070 | 0 | if (SupportsApzTouchInput()) { |
3071 | 0 | aObj.DefineProperty("ApzTouchInput", 1); |
3072 | 0 | } |
3073 | 0 |
|
3074 | 0 | if (SupportsApzDragInput()) { |
3075 | 0 | aObj.DefineProperty("ApzDragInput", 1); |
3076 | 0 | } |
3077 | 0 |
|
3078 | 0 | if (SupportsApzKeyboardInput() && !gfxPrefs::AccessibilityBrowseWithCaret()) { |
3079 | 0 | aObj.DefineProperty("ApzKeyboardInput", 1); |
3080 | 0 | } |
3081 | 0 |
|
3082 | 0 | if (SupportsApzAutoscrolling()) { |
3083 | 0 | aObj.DefineProperty("ApzAutoscrollInput", 1); |
3084 | 0 | } |
3085 | 0 | } |
3086 | | |
3087 | | void |
3088 | | gfxPlatform::GetTilesSupportInfo(mozilla::widget::InfoObject& aObj) |
3089 | 0 | { |
3090 | 0 | if (!gfxPrefs::LayersTilesEnabled()) { |
3091 | 0 | return; |
3092 | 0 | } |
3093 | 0 | |
3094 | 0 | IntSize tileSize = gfxVars::TileSize(); |
3095 | 0 | aObj.DefineProperty("TileHeight", tileSize.height); |
3096 | 0 | aObj.DefineProperty("TileWidth", tileSize.width); |
3097 | 0 | } |
3098 | | |
3099 | | /*static*/ bool |
3100 | | gfxPlatform::AsyncPanZoomEnabled() |
3101 | 0 | { |
3102 | 0 | #if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT) |
3103 | 0 | // For XUL applications (everything but Firefox on Android) |
3104 | 0 | // we only want to use APZ when E10S is enabled. If |
3105 | 0 | // we ever get input events off the main thread we can consider relaxing |
3106 | 0 | // this requirement. |
3107 | 0 | if (!BrowserTabsRemoteAutostart()) { |
3108 | 0 | return false; |
3109 | 0 | } |
3110 | 0 | #endif |
3111 | | #ifdef MOZ_WIDGET_ANDROID |
3112 | | return true; |
3113 | | #else |
3114 | 0 | if (!gfxPrefs::SingletonExists()) { |
3115 | 0 | // Make sure the gfxPrefs has been initialized before reading from it. |
3116 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
3117 | 0 | gfxPrefs::GetSingleton(); |
3118 | 0 | } |
3119 | 0 | return gfxPrefs::AsyncPanZoomEnabledDoNotUseDirectly(); |
3120 | 0 | #endif |
3121 | 0 | } |
3122 | | |
3123 | | /*static*/ bool |
3124 | | gfxPlatform::PerfWarnings() |
3125 | 0 | { |
3126 | 0 | return gfxPrefs::PerfWarnings(); |
3127 | 0 | } |
3128 | | |
3129 | | void |
3130 | | gfxPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aBackends) |
3131 | 0 | { |
3132 | 0 | if (gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING)) { |
3133 | 0 | aBackends.AppendElement(LayersBackend::LAYERS_OPENGL); |
3134 | 0 | } |
3135 | 0 | else { |
3136 | 0 | static int tell_me_once = 0; |
3137 | 0 | if (!tell_me_once) { |
3138 | 0 | NS_WARNING("OpenGL-accelerated layers are not supported on this system"); |
3139 | 0 | tell_me_once = 1; |
3140 | 0 | } |
3141 | | #ifdef MOZ_WIDGET_ANDROID |
3142 | | MOZ_CRASH("OpenGL-accelerated layers are a hard requirement on this platform. " |
3143 | | "Cannot continue without support for them"); |
3144 | | #endif |
3145 | | } |
3146 | 0 | } |
3147 | | |
3148 | | void |
3149 | | gfxPlatform::GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layers::LayersBackend>& aBackends) |
3150 | 0 | { |
3151 | 0 | if (useAcceleration) { |
3152 | 0 | GetAcceleratedCompositorBackends(aBackends); |
3153 | 0 | } |
3154 | 0 | aBackends.AppendElement(LayersBackend::LAYERS_BASIC); |
3155 | 0 | } |
3156 | | |
3157 | | void |
3158 | | gfxPlatform::NotifyCompositorCreated(LayersBackend aBackend) |
3159 | 0 | { |
3160 | 0 | if (mCompositorBackend == aBackend) { |
3161 | 0 | return; |
3162 | 0 | } |
3163 | 0 | |
3164 | 0 | if (mCompositorBackend != LayersBackend::LAYERS_NONE) { |
3165 | 0 | gfxCriticalNote << "Compositors might be mixed (" |
3166 | 0 | << int(mCompositorBackend) << "," << int(aBackend) << ")"; |
3167 | 0 | } |
3168 | 0 |
|
3169 | 0 | // Set the backend before we notify so it's available immediately. |
3170 | 0 | mCompositorBackend = aBackend; |
3171 | 0 |
|
3172 | 0 | // Notify that we created a compositor, so telemetry can update. |
3173 | 0 | NS_DispatchToMainThread( |
3174 | 0 | NS_NewRunnableFunction("gfxPlatform::NotifyCompositorCreated", [] { |
3175 | 0 | if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) { |
3176 | 0 | obsvc->NotifyObservers(nullptr, "compositor:created", nullptr); |
3177 | 0 | } |
3178 | 0 | })); |
3179 | 0 | } |
3180 | | |
3181 | | /* static */ void |
3182 | | gfxPlatform::NotifyGPUProcessDisabled() |
3183 | 0 | { |
3184 | 0 | if (gfxConfig::IsEnabled(Feature::WEBRENDER)) { |
3185 | 0 | gfxConfig::GetFeature(Feature::WEBRENDER).ForceDisable( |
3186 | 0 | FeatureStatus::Unavailable, |
3187 | 0 | "GPU Process is disabled", |
3188 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED")); |
3189 | 0 | gfxVars::SetUseWebRender(false); |
3190 | 0 | } |
3191 | 0 | } |
3192 | | |
3193 | | void |
3194 | | gfxPlatform::FetchAndImportContentDeviceData() |
3195 | 0 | { |
3196 | 0 | MOZ_ASSERT(XRE_IsContentProcess()); |
3197 | 0 |
|
3198 | 0 | if (gContentDeviceInitData) { |
3199 | 0 | ImportContentDeviceData(*gContentDeviceInitData); |
3200 | 0 | return; |
3201 | 0 | } |
3202 | 0 | |
3203 | 0 | mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton(); |
3204 | 0 |
|
3205 | 0 | mozilla::gfx::ContentDeviceData data; |
3206 | 0 | cc->SendGetGraphicsDeviceInitData(&data); |
3207 | 0 |
|
3208 | 0 | ImportContentDeviceData(data); |
3209 | 0 | } |
3210 | | |
3211 | | void |
3212 | | gfxPlatform::ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData) |
3213 | 0 | { |
3214 | 0 | MOZ_ASSERT(XRE_IsContentProcess()); |
3215 | 0 |
|
3216 | 0 | const DevicePrefs& prefs = aData.prefs(); |
3217 | 0 | gfxConfig::Inherit(Feature::HW_COMPOSITING, prefs.hwCompositing()); |
3218 | 0 | gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, prefs.oglCompositing()); |
3219 | 0 | } |
3220 | | |
3221 | | void |
3222 | | gfxPlatform::BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut) |
3223 | 0 | { |
3224 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
3225 | 0 |
|
3226 | 0 | // Make sure our settings are synchronized from the GPU process. |
3227 | 0 | GPUProcessManager::Get()->EnsureGPUReady(); |
3228 | 0 |
|
3229 | 0 | aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING); |
3230 | 0 | aOut->prefs().oglCompositing() = gfxConfig::GetValue(Feature::OPENGL_COMPOSITING); |
3231 | 0 | } |
3232 | | |
3233 | | void |
3234 | | gfxPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData) |
3235 | 0 | { |
3236 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
3237 | 0 |
|
3238 | 0 | gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing()); |
3239 | 0 | gfxConfig::ImportChange(Feature::ADVANCED_LAYERS, aData.advancedLayers()); |
3240 | 0 | } |
3241 | | |
3242 | | bool |
3243 | | gfxPlatform::SupportsApzTouchInput() const |
3244 | 0 | { |
3245 | 0 | return dom::TouchEvent::PrefEnabled(nullptr); |
3246 | 0 | } |
3247 | | |
3248 | | bool |
3249 | | gfxPlatform::SupportsApzDragInput() const |
3250 | 0 | { |
3251 | 0 | return gfxPrefs::APZDragEnabled(); |
3252 | 0 | } |
3253 | | |
3254 | | bool |
3255 | | gfxPlatform::SupportsApzKeyboardInput() const |
3256 | 0 | { |
3257 | 0 | return gfxPrefs::APZKeyboardEnabled(); |
3258 | 0 | } |
3259 | | |
3260 | | bool |
3261 | | gfxPlatform::SupportsApzAutoscrolling() const |
3262 | 0 | { |
3263 | 0 | return gfxPrefs::APZAutoscrollEnabled(); |
3264 | 0 | } |
3265 | | |
3266 | | void |
3267 | | gfxPlatform::InitOpenGLConfig() |
3268 | 0 | { |
3269 | | #ifdef XP_WIN |
3270 | | // Don't enable by default on Windows, since it could show up in about:support even |
3271 | | // though it'll never get used. Only attempt if user enables the pref |
3272 | | if (!Preferences::GetBool("layers.prefer-opengl")){ |
3273 | | return; |
3274 | | } |
3275 | | #endif |
3276 | |
|
3277 | 0 | FeatureState& openGLFeature = gfxConfig::GetFeature(Feature::OPENGL_COMPOSITING); |
3278 | 0 |
|
3279 | 0 | // Check to see hw comp supported |
3280 | 0 | if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) { |
3281 | 0 | openGLFeature.DisableByDefault(FeatureStatus::Unavailable, "Hardware compositing is disabled", |
3282 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_OPENGL_NEED_HWCOMP")); |
3283 | 0 | return; |
3284 | 0 | } |
3285 | 0 |
|
3286 | | #ifdef XP_WIN |
3287 | | openGLFeature.SetDefaultFromPref( |
3288 | | gfxPrefs::GetLayersPreferOpenGLPrefName(), |
3289 | | true, |
3290 | | gfxPrefs::GetLayersPreferOpenGLPrefDefault()); |
3291 | | #else |
3292 | 0 | openGLFeature.EnableByDefault(); |
3293 | 0 | #endif |
3294 | 0 |
|
3295 | 0 | // When layers acceleration is force-enabled, enable it even for blacklisted |
3296 | 0 | // devices. |
3297 | 0 | if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) { |
3298 | 0 | openGLFeature.UserForceEnable("Force-enabled by pref"); |
3299 | 0 | return; |
3300 | 0 | } |
3301 | 0 | |
3302 | 0 | nsCString message; |
3303 | 0 | nsCString failureId; |
3304 | 0 | if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &message, failureId)) { |
3305 | 0 | openGLFeature.Disable(FeatureStatus::Blacklisted, message.get(), failureId); |
3306 | 0 | } |
3307 | 0 | } |
3308 | | |
3309 | | bool |
3310 | | gfxPlatform::IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage, nsCString& aFailureId) |
3311 | 0 | { |
3312 | 0 | nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); |
3313 | 0 | if (!gfxInfo) { |
3314 | 0 | return true; |
3315 | 0 | } |
3316 | 0 | |
3317 | 0 | int32_t status; |
3318 | 0 | if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) && |
3319 | 0 | status != nsIGfxInfo::FEATURE_STATUS_OK) |
3320 | 0 | { |
3321 | 0 | aOutMessage->AssignLiteral("#BLOCKLIST_"); |
3322 | 0 | aOutMessage->AppendASCII(aFailureId.get()); |
3323 | 0 | return false; |
3324 | 0 | } |
3325 | 0 | |
3326 | 0 | return true; |
3327 | 0 | } |