1 /* vim: se cin sw=2 ts=2 et : */
2 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/ArrayUtils.h"
10 #include "GfxInfoBase.h"
12 #include "GfxInfoWebGL.h"
13 #include "GfxDriverInfo.h"
15 #include "nsCOMArray.h"
17 #include "nsUnicharUtils.h"
18 #include "nsVersionComparator.h"
19 #include "mozilla/Services.h"
20 #include "mozilla/Observer.h"
21 #include "nsIObserver.h"
22 #include "nsIObserverService.h"
23 #include "nsIDOMElement.h"
24 #include "nsIDOMHTMLCollection.h"
25 #include "nsIDOMNode.h"
26 #include "nsIDOMNodeList.h"
28 #include "nsXULAppAPI.h"
29 #include "nsIXULAppInfo.h"
30 #include "mozilla/Preferences.h"
31 #include "mozilla/dom/ContentChild.h"
32 #include "mozilla/gfx/2D.h"
33 #include "mozilla/gfx/GPUProcessManager.h"
34 #include "mozilla/gfx/Logging.h"
35 #include "mozilla/gfx/gfxVars.h"
36 #include "MediaPrefs.h"
38 #include "gfxPlatform.h"
39 #include "gfxConfig.h"
40 #include "DriverCrashGuard.h"
42 #if defined(MOZ_CRASHREPORTER)
43 #include "nsExceptionHandler.h"
46 using namespace mozilla::widget
;
47 using namespace mozilla
;
48 using mozilla::MutexAutoLock
;
50 nsTArray
<GfxDriverInfo
>* GfxInfoBase::mDriverInfo
;
51 nsTArray
<dom::GfxInfoFeatureStatus
>* GfxInfoBase::mFeatureStatus
;
52 bool GfxInfoBase::mDriverInfoObserverInitialized
;
53 bool GfxInfoBase::mShutdownOccurred
;
55 // Observes for shutdown so that the child GfxDriverInfo list is freed.
56 class ShutdownObserver
: public nsIObserver
58 virtual ~ShutdownObserver() {}
65 NS_IMETHOD
Observe(nsISupports
*subject
, const char *aTopic
,
66 const char16_t
*aData
) override
68 MOZ_ASSERT(strcmp(aTopic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
) == 0);
70 delete GfxInfoBase::mDriverInfo
;
71 GfxInfoBase::mDriverInfo
= nullptr;
73 delete GfxInfoBase::mFeatureStatus
;
74 GfxInfoBase::mFeatureStatus
= nullptr;
76 for (uint32_t i
= 0; i
< DeviceFamilyMax
; i
++)
77 delete GfxDriverInfo::mDeviceFamilies
[i
];
79 for (uint32_t i
= 0; i
< DeviceVendorMax
; i
++)
80 delete GfxDriverInfo::mDeviceVendors
[i
];
82 GfxInfoBase::mShutdownOccurred
= true;
88 NS_IMPL_ISUPPORTS(ShutdownObserver
, nsIObserver
)
90 void InitGfxDriverInfoShutdownObserver()
92 if (GfxInfoBase::mDriverInfoObserverInitialized
)
95 GfxInfoBase::mDriverInfoObserverInitialized
= true;
97 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
98 if (!observerService
) {
99 NS_WARNING("Could not get observer service!");
103 ShutdownObserver
*obs
= new ShutdownObserver();
104 observerService
->AddObserver(obs
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
107 using namespace mozilla::widget
;
108 using namespace mozilla::gfx
;
109 using namespace mozilla
;
111 NS_IMPL_ISUPPORTS(GfxInfoBase
, nsIGfxInfo
, nsIObserver
, nsISupportsWeakReference
)
113 #define BLACKLIST_PREF_BRANCH "gfx.blacklist."
114 #define SUGGESTED_VERSION_PREF BLACKLIST_PREF_BRANCH "suggested-driver-version"
115 #define BLACKLIST_ENTRY_TAG_NAME "gfxBlacklistEntry"
118 GetPrefNameForFeature(int32_t aFeature
)
120 const char* name
= nullptr;
122 case nsIGfxInfo::FEATURE_DIRECT2D
:
123 name
= BLACKLIST_PREF_BRANCH
"direct2d";
125 case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
:
126 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d9";
128 case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
:
129 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d10";
131 case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
:
132 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d10-1";
134 case nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
:
135 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d11";
137 case nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
:
138 name
= BLACKLIST_PREF_BRANCH
"direct3d11angle";
140 case nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING
:
141 name
= BLACKLIST_PREF_BRANCH
"hardwarevideodecoding";
143 case nsIGfxInfo::FEATURE_OPENGL_LAYERS
:
144 name
= BLACKLIST_PREF_BRANCH
"layers.opengl";
146 case nsIGfxInfo::FEATURE_WEBGL_OPENGL
:
147 name
= BLACKLIST_PREF_BRANCH
"webgl.opengl";
149 case nsIGfxInfo::FEATURE_WEBGL_ANGLE
:
150 name
= BLACKLIST_PREF_BRANCH
"webgl.angle";
152 case nsIGfxInfo::FEATURE_WEBGL_MSAA
:
153 name
= BLACKLIST_PREF_BRANCH
"webgl.msaa";
155 case nsIGfxInfo::FEATURE_STAGEFRIGHT
:
156 name
= BLACKLIST_PREF_BRANCH
"stagefright";
158 case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION
:
159 name
= BLACKLIST_PREF_BRANCH
"webrtc.hw.acceleration";
161 case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE
:
162 name
= BLACKLIST_PREF_BRANCH
"webrtc.hw.acceleration.encode";
164 case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE
:
165 name
= BLACKLIST_PREF_BRANCH
"webrtc.hw.acceleration.decode";
167 case nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION
:
168 name
= BLACKLIST_PREF_BRANCH
"canvas2d.acceleration";
170 case nsIGfxInfo::FEATURE_WEBGL2
:
171 name
= BLACKLIST_PREF_BRANCH
"webgl2";
173 case nsIGfxInfo::FEATURE_ADVANCED_LAYERS
:
174 name
= BLACKLIST_PREF_BRANCH
"layers.advanced";
176 case nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX
:
177 name
= BLACKLIST_PREF_BRANCH
"d3d11.keyed.mutex";
179 case nsIGfxInfo::FEATURE_VP8_HW_DECODE
:
180 case nsIGfxInfo::FEATURE_VP9_HW_DECODE
:
181 case nsIGfxInfo::FEATURE_DX_INTEROP2
:
182 case nsIGfxInfo::FEATURE_GPU_PROCESS
:
183 // We don't provide prefs for these features.
186 MOZ_ASSERT_UNREACHABLE("Unexpected nsIGfxInfo feature?!");
193 // Returns the value of the pref for the relevant feature in aValue.
194 // If the pref doesn't exist, aValue is not touched, and returns false.
196 GetPrefValueForFeature(int32_t aFeature
, int32_t& aValue
, nsACString
& aFailureId
)
198 const char *prefname
= GetPrefNameForFeature(aFeature
);
202 aValue
= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
;
203 if (!NS_SUCCEEDED(Preferences::GetInt(prefname
, &aValue
))) {
207 nsCString
failureprefname(prefname
);
208 failureprefname
+= ".failureid";
209 nsAutoCString failureValue
;
210 nsresult rv
= Preferences::GetCString(failureprefname
.get(), failureValue
);
211 if (NS_SUCCEEDED(rv
)) {
212 aFailureId
= failureValue
.get();
214 aFailureId
= "FEATURE_FAILURE_BLACKLIST_PREF";
221 SetPrefValueForFeature(int32_t aFeature
, int32_t aValue
, const nsACString
& aFailureId
)
223 const char *prefname
= GetPrefNameForFeature(aFeature
);
227 Preferences::SetInt(prefname
, aValue
);
228 if (!aFailureId
.IsEmpty()) {
229 nsCString
failureprefname(prefname
);
230 failureprefname
+= ".failureid";
231 Preferences::SetCString(failureprefname
.get(), aFailureId
);
236 RemovePrefForFeature(int32_t aFeature
)
238 const char *prefname
= GetPrefNameForFeature(aFeature
);
242 Preferences::ClearUser(prefname
);
246 GetPrefValueForDriverVersion(nsCString
& aVersion
)
248 return NS_SUCCEEDED(Preferences::GetCString(SUGGESTED_VERSION_PREF
,
253 SetPrefValueForDriverVersion(const nsAString
& aVersion
)
255 Preferences::SetString(SUGGESTED_VERSION_PREF
, aVersion
);
259 RemovePrefForDriverVersion()
261 Preferences::ClearUser(SUGGESTED_VERSION_PREF
);
265 static OperatingSystem
266 BlacklistOSToOperatingSystem(const nsAString
& os
)
268 if (os
.EqualsLiteral("WINNT 6.1"))
269 return OperatingSystem::Windows7
;
270 else if (os
.EqualsLiteral("WINNT 6.2"))
271 return OperatingSystem::Windows8
;
272 else if (os
.EqualsLiteral("WINNT 6.3"))
273 return OperatingSystem::Windows8_1
;
274 else if (os
.EqualsLiteral("WINNT 10.0"))
275 return OperatingSystem::Windows10
;
276 else if (os
.EqualsLiteral("Linux"))
277 return OperatingSystem::Linux
;
278 else if (os
.EqualsLiteral("Darwin 9"))
279 return OperatingSystem::OSX10_5
;
280 else if (os
.EqualsLiteral("Darwin 10"))
281 return OperatingSystem::OSX10_6
;
282 else if (os
.EqualsLiteral("Darwin 11"))
283 return OperatingSystem::OSX10_7
;
284 else if (os
.EqualsLiteral("Darwin 12"))
285 return OperatingSystem::OSX10_8
;
286 else if (os
.EqualsLiteral("Darwin 13"))
287 return OperatingSystem::OSX10_9
;
288 else if (os
.EqualsLiteral("Darwin 14"))
289 return OperatingSystem::OSX10_10
;
290 else if (os
.EqualsLiteral("Darwin 15"))
291 return OperatingSystem::OSX10_11
;
292 else if (os
.EqualsLiteral("Darwin 16"))
293 return OperatingSystem::OSX10_12
;
294 else if (os
.EqualsLiteral("Android"))
295 return OperatingSystem::Android
;
296 // For historical reasons, "All" in blocklist means "All Windows"
297 else if (os
.EqualsLiteral("All"))
298 return OperatingSystem::Windows
;
300 return OperatingSystem::Unknown
;
303 static GfxDeviceFamily
*
304 BlacklistDevicesToDeviceFamily(nsTArray
<nsCString
>& devices
)
306 if (devices
.Length() == 0)
309 // For each device, get its device ID, and return a freshly-allocated
310 // GfxDeviceFamily with the contents of that array.
311 GfxDeviceFamily
* deviceIds
= new GfxDeviceFamily
;
313 for (uint32_t i
= 0; i
< devices
.Length(); ++i
) {
314 // We make sure we don't add any "empty" device entries to the array, so
315 // we don't need to check if devices[i] is empty.
316 deviceIds
->AppendElement(NS_ConvertUTF8toUTF16(devices
[i
]));
323 BlacklistFeatureToGfxFeature(const nsAString
& aFeature
)
325 MOZ_ASSERT(!aFeature
.IsEmpty());
326 if (aFeature
.EqualsLiteral("DIRECT2D"))
327 return nsIGfxInfo::FEATURE_DIRECT2D
;
328 else if (aFeature
.EqualsLiteral("DIRECT3D_9_LAYERS"))
329 return nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
;
330 else if (aFeature
.EqualsLiteral("DIRECT3D_10_LAYERS"))
331 return nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
;
332 else if (aFeature
.EqualsLiteral("DIRECT3D_10_1_LAYERS"))
333 return nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
;
334 else if (aFeature
.EqualsLiteral("DIRECT3D_11_LAYERS"))
335 return nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
;
336 else if (aFeature
.EqualsLiteral("DIRECT3D_11_ANGLE"))
337 return nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
;
338 else if (aFeature
.EqualsLiteral("HARDWARE_VIDEO_DECODING"))
339 return nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING
;
340 else if (aFeature
.EqualsLiteral("OPENGL_LAYERS"))
341 return nsIGfxInfo::FEATURE_OPENGL_LAYERS
;
342 else if (aFeature
.EqualsLiteral("WEBGL_OPENGL"))
343 return nsIGfxInfo::FEATURE_WEBGL_OPENGL
;
344 else if (aFeature
.EqualsLiteral("WEBGL_ANGLE"))
345 return nsIGfxInfo::FEATURE_WEBGL_ANGLE
;
346 else if (aFeature
.EqualsLiteral("WEBGL_MSAA"))
347 return nsIGfxInfo::FEATURE_WEBGL_MSAA
;
348 else if (aFeature
.EqualsLiteral("STAGEFRIGHT"))
349 return nsIGfxInfo::FEATURE_STAGEFRIGHT
;
350 else if (aFeature
.EqualsLiteral("WEBRTC_HW_ACCELERATION_ENCODE"))
351 return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE
;
352 else if (aFeature
.EqualsLiteral("WEBRTC_HW_ACCELERATION_DECODE"))
353 return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE
;
354 else if (aFeature
.EqualsLiteral("WEBRTC_HW_ACCELERATION"))
355 return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION
;
356 else if (aFeature
.EqualsLiteral("CANVAS2D_ACCELERATION"))
357 return nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION
;
358 else if (aFeature
.EqualsLiteral("WEBGL2"))
359 return nsIGfxInfo::FEATURE_WEBGL2
;
360 else if (aFeature
.EqualsLiteral("ADVANCED_LAYERS"))
361 return nsIGfxInfo::FEATURE_ADVANCED_LAYERS
;
362 else if (aFeature
.EqualsLiteral("D3D11_KEYED_MUTEX"))
363 return nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX
;
365 // If we don't recognize the feature, it may be new, and something
366 // this version doesn't understand. So, nothing to do. This is
367 // different from feature not being specified at all, in which case
368 // this method should not get called and we should continue with the
369 // "all features" blocklisting.
374 BlacklistFeatureStatusToGfxFeatureStatus(const nsAString
& aStatus
)
376 if (aStatus
.EqualsLiteral("STATUS_OK"))
377 return nsIGfxInfo::FEATURE_STATUS_OK
;
378 else if (aStatus
.EqualsLiteral("BLOCKED_DRIVER_VERSION"))
379 return nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
;
380 else if (aStatus
.EqualsLiteral("BLOCKED_DEVICE"))
381 return nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
382 else if (aStatus
.EqualsLiteral("DISCOURAGED"))
383 return nsIGfxInfo::FEATURE_DISCOURAGED
;
384 else if (aStatus
.EqualsLiteral("BLOCKED_OS_VERSION"))
385 return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION
;
387 // Do not allow it to set STATUS_UNKNOWN. Also, we are not
388 // expecting the "mismatch" status showing up here.
390 return nsIGfxInfo::FEATURE_STATUS_OK
;
393 static VersionComparisonOp
394 BlacklistComparatorToComparisonOp(const nsAString
& op
)
396 if (op
.EqualsLiteral("LESS_THAN"))
397 return DRIVER_LESS_THAN
;
398 else if (op
.EqualsLiteral("BUILD_ID_LESS_THAN"))
399 return DRIVER_BUILD_ID_LESS_THAN
;
400 else if (op
.EqualsLiteral("LESS_THAN_OR_EQUAL"))
401 return DRIVER_LESS_THAN_OR_EQUAL
;
402 else if (op
.EqualsLiteral("BUILD_ID_LESS_THAN_OR_EQUAL"))
403 return DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL
;
404 else if (op
.EqualsLiteral("GREATER_THAN"))
405 return DRIVER_GREATER_THAN
;
406 else if (op
.EqualsLiteral("GREATER_THAN_OR_EQUAL"))
407 return DRIVER_GREATER_THAN_OR_EQUAL
;
408 else if (op
.EqualsLiteral("EQUAL"))
410 else if (op
.EqualsLiteral("NOT_EQUAL"))
411 return DRIVER_NOT_EQUAL
;
412 else if (op
.EqualsLiteral("BETWEEN_EXCLUSIVE"))
413 return DRIVER_BETWEEN_EXCLUSIVE
;
414 else if (op
.EqualsLiteral("BETWEEN_INCLUSIVE"))
415 return DRIVER_BETWEEN_INCLUSIVE
;
416 else if (op
.EqualsLiteral("BETWEEN_INCLUSIVE_START"))
417 return DRIVER_BETWEEN_INCLUSIVE_START
;
419 return DRIVER_COMPARISON_IGNORED
;
424 Deserialize Blacklist entries from string.
426 os:WINNT 6.0\tvendor:0x8086\tdevices:0x2582,0x2782\tfeature:DIRECT3D_10_LAYERS\tfeatureStatus:BLOCKED_DRIVER_VERSION\tdriverVersion:8.52.322.2202\tdriverVersionComparator:LESS_THAN_OR_EQUAL
429 BlacklistEntryToDriverInfo(nsCString
& aBlacklistEntry
,
430 GfxDriverInfo
& aDriverInfo
)
432 // If we get an application version to be zero, something is not working
433 // and we are not going to bother checking the blocklist versions.
434 // See TestGfxWidgets.cpp for how version comparison works.
435 // <versionRange minVersion="42.0a1" maxVersion="45.0"></versionRange>
436 static mozilla::Version
zeroV("0");
437 static mozilla::Version
appV(GfxInfoBase::GetApplicationVersion().get());
439 gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Invalid application version " << GfxInfoBase::GetApplicationVersion().get();
442 nsTArray
<nsCString
> keyValues
;
443 ParseString(aBlacklistEntry
, '\t', keyValues
);
445 aDriverInfo
.mRuleId
= NS_LITERAL_CSTRING("FEATURE_FAILURE_DL_BLACKLIST_NO_ID");
447 for (uint32_t i
= 0; i
< keyValues
.Length(); ++i
) {
448 nsCString keyValue
= keyValues
[i
];
449 nsTArray
<nsCString
> splitted
;
450 ParseString(keyValue
, ':', splitted
);
451 if (splitted
.Length() != 2) {
452 // If we don't recognize the input data, we do not want to proceed.
453 gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Unrecognized data " << keyValue
.get();
456 nsCString key
= splitted
[0];
457 nsCString value
= splitted
[1];
458 NS_ConvertUTF8toUTF16
dataValue(value
);
460 if (value
.Length() == 0) {
461 // Safety check for empty values.
462 gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Empty value for " << key
.get();
466 if (key
.EqualsLiteral("blockID")) {
467 nsCString blockIdStr
= NS_LITERAL_CSTRING("FEATURE_FAILURE_DL_BLACKLIST_") + value
;
468 aDriverInfo
.mRuleId
= blockIdStr
.get();
469 } else if (key
.EqualsLiteral("os")) {
470 aDriverInfo
.mOperatingSystem
= BlacklistOSToOperatingSystem(dataValue
);
471 } else if (key
.EqualsLiteral("osversion")) {
472 aDriverInfo
.mOperatingSystemVersion
= strtoul(value
.get(), nullptr, 10);
473 } else if (key
.EqualsLiteral("vendor")) {
474 aDriverInfo
.mAdapterVendor
= dataValue
;
475 } else if (key
.EqualsLiteral("feature")) {
476 aDriverInfo
.mFeature
= BlacklistFeatureToGfxFeature(dataValue
);
477 if (aDriverInfo
.mFeature
< 0) {
478 // If we don't recognize the feature, we do not want to proceed.
479 gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Unrecognized feature " << value
.get();
482 } else if (key
.EqualsLiteral("featureStatus")) {
483 aDriverInfo
.mFeatureStatus
= BlacklistFeatureStatusToGfxFeatureStatus(dataValue
);
484 } else if (key
.EqualsLiteral("driverVersion")) {
486 if (ParseDriverVersion(dataValue
, &version
))
487 aDriverInfo
.mDriverVersion
= version
;
488 } else if (key
.EqualsLiteral("driverVersionMax")) {
490 if (ParseDriverVersion(dataValue
, &version
))
491 aDriverInfo
.mDriverVersionMax
= version
;
492 } else if (key
.EqualsLiteral("driverVersionComparator")) {
493 aDriverInfo
.mComparisonOp
= BlacklistComparatorToComparisonOp(dataValue
);
494 } else if (key
.EqualsLiteral("model")) {
495 aDriverInfo
.mModel
= dataValue
;
496 } else if (key
.EqualsLiteral("product")) {
497 aDriverInfo
.mProduct
= dataValue
;
498 } else if (key
.EqualsLiteral("manufacturer")) {
499 aDriverInfo
.mManufacturer
= dataValue
;
500 } else if (key
.EqualsLiteral("hardware")) {
501 aDriverInfo
.mHardware
= dataValue
;
502 } else if (key
.EqualsLiteral("versionRange")) {
503 nsTArray
<nsCString
> versionRange
;
504 ParseString(value
, ',', versionRange
);
505 if (versionRange
.Length() != 2) {
506 gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false)) << "Unrecognized versionRange " << value
.get();
509 nsCString minValue
= versionRange
[0];
510 nsCString maxValue
= versionRange
[1];
512 mozilla::Version
minV(minValue
.get());
513 mozilla::Version
maxV(maxValue
.get());
515 if (minV
> zeroV
&& !(appV
>= minV
)) {
516 // The version of the application is less than the minimal version
517 // this blocklist entry applies to, so we can just ignore it by
518 // returning false and letting the caller deal with it.
521 if (maxV
> zeroV
&& !(appV
<= maxV
)) {
522 // The version of the application is more than the maximal version
523 // this blocklist entry applies to, so we can just ignore it by
524 // returning false and letting the caller deal with it.
527 } else if (key
.EqualsLiteral("devices")) {
528 nsTArray
<nsCString
> devices
;
529 ParseString(value
, ',', devices
);
530 GfxDeviceFamily
* deviceIds
= BlacklistDevicesToDeviceFamily(devices
);
532 // Get GfxDriverInfo to adopt the devices array we created.
533 aDriverInfo
.mDeleteDevices
= true;
534 aDriverInfo
.mDevices
= deviceIds
;
537 // We explicitly ignore unknown elements.
544 BlacklistEntriesToDriverInfo(nsTArray
<nsCString
>& aBlacklistEntries
,
545 nsTArray
<GfxDriverInfo
>& aDriverInfo
)
548 aDriverInfo
.SetLength(aBlacklistEntries
.Length());
550 for (uint32_t i
= 0; i
< aBlacklistEntries
.Length(); ++i
) {
551 nsCString blacklistEntry
= aBlacklistEntries
[i
];
553 if (BlacklistEntryToDriverInfo(blacklistEntry
, di
)) {
555 // Prevent di falling out of scope from destroying the devices.
556 di
.mDeleteDevices
= false;
562 GfxInfoBase::Observe(nsISupports
* aSubject
, const char* aTopic
,
563 const char16_t
* aData
)
565 if (strcmp(aTopic
, "blocklist-data-gfxItems") == 0) {
566 nsTArray
<GfxDriverInfo
> driverInfo
;
567 nsTArray
<nsCString
> blacklistEntries
;
568 nsCString utf8Data
= NS_ConvertUTF16toUTF8(aData
);
569 if (utf8Data
.Length() > 0) {
570 ParseString(utf8Data
, '\n', blacklistEntries
);
572 BlacklistEntriesToDriverInfo(blacklistEntries
, driverInfo
);
573 EvaluateDownloadedBlacklist(driverInfo
);
579 GfxInfoBase::GfxInfoBase()
580 : mMutex("GfxInfoBase")
584 GfxInfoBase::~GfxInfoBase()
591 InitGfxDriverInfoShutdownObserver();
592 gfxPrefs::GetSingleton();
593 MediaPrefs::GetSingleton();
595 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
597 os
->AddObserver(this, "blocklist-data-gfxItems", true);
604 GfxInfoBase::GetFeatureStatus(int32_t aFeature
, nsACString
& aFailureId
, int32_t* aStatus
)
606 int32_t blocklistAll
= gfxPrefs::BlocklistAll();
607 if (blocklistAll
> 0) {
608 gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Forcing blocklisting all features";
609 *aStatus
= FEATURE_BLOCKED_DEVICE
;
610 aFailureId
= "FEATURE_FAILURE_BLOCK_ALL";
612 } else if (blocklistAll
< 0) {
613 gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Ignoring any feature blocklisting.";
614 *aStatus
= FEATURE_STATUS_OK
;
618 if (GetPrefValueForFeature(aFeature
, *aStatus
, aFailureId
)) {
622 if (XRE_IsContentProcess()) {
623 // Use the cached data received from the parent process.
624 MOZ_ASSERT(mFeatureStatus
);
625 bool success
= false;
626 for (const auto& fs
: *mFeatureStatus
) {
627 if (fs
.feature() == aFeature
) {
628 aFailureId
= fs
.failureId();
629 *aStatus
= fs
.status();
634 return success
? NS_OK
: NS_ERROR_FAILURE
;
638 nsTArray
<GfxDriverInfo
> driverInfo
;
639 nsresult rv
= GetFeatureStatusImpl(aFeature
, aStatus
, version
, driverInfo
, aFailureId
);
643 // Matching OS go somewhat beyond the simple equality check because of the
644 // "All Windows" and "All OS X" variations.
646 // aBlockedOS is describing the system(s) we are trying to block.
647 // aSystemOS is describing the system we are running on.
649 // aSystemOS should not be "Windows" or "OSX" - it should be set to
650 // a particular version instead.
651 // However, it is valid for aBlockedOS to be one of those generic values,
652 // as we could be blocking all of the versions.
654 MatchingOperatingSystems(OperatingSystem aBlockedOS
, OperatingSystem aSystemOS
)
656 MOZ_ASSERT(aSystemOS
!= OperatingSystem::Windows
&&
657 aSystemOS
!= OperatingSystem::OSX
);
659 // If the block entry OS is unknown, it doesn't match
660 if (aBlockedOS
== OperatingSystem::Unknown
) {
665 if (aBlockedOS
== OperatingSystem::Windows
) {
666 // We do want even "unknown" aSystemOS to fall under "all windows"
671 #if defined (XP_MACOSX)
672 if (aBlockedOS
== OperatingSystem::OSX
) {
673 // We do want even "unknown" aSystemOS to fall under "all OS X"
678 return aSystemOS
== aBlockedOS
;
682 GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray
<GfxDriverInfo
>& info
,
683 nsAString
& aSuggestedVersion
,
685 nsACString
& aFailureId
,
688 int32_t status
= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
;
690 // Get the adapters once then reuse below
691 nsAutoString adapterVendorID
[2];
692 nsAutoString adapterDeviceID
[2];
693 nsAutoString adapterDriverVersionString
[2];
694 bool adapterInfoFailed
[2];
696 adapterInfoFailed
[0] = (NS_FAILED(GetAdapterVendorID(adapterVendorID
[0])) ||
697 NS_FAILED(GetAdapterDeviceID(adapterDeviceID
[0])) ||
698 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString
[0])));
699 adapterInfoFailed
[1] = (NS_FAILED(GetAdapterVendorID2(adapterVendorID
[1])) ||
700 NS_FAILED(GetAdapterDeviceID2(adapterDeviceID
[1])) ||
701 NS_FAILED(GetAdapterDriverVersion2(adapterDriverVersionString
[1])));
702 // No point in going on if we don't have adapter info
703 if (adapterInfoFailed
[0] && adapterInfoFailed
[1]) {
707 #if defined(XP_WIN) || defined(ANDROID)
708 uint64_t driverVersion
[2] = {0, 0};
709 if (!adapterInfoFailed
[0]) {
710 ParseDriverVersion(adapterDriverVersionString
[0], &driverVersion
[0]);
712 if (!adapterInfoFailed
[1]) {
713 ParseDriverVersion(adapterDriverVersionString
[1], &driverVersion
[1]);
718 for (; i
< info
.Length(); i
++) {
719 // If we don't have the info for this GPU, no need to check further.
720 // It is unclear that we would ever have a mixture of 1st and 2nd
721 // GPU, but leaving the code in for that possibility for now.
722 // (Actually, currently mGpu2 will never be true, so this can
723 // be optimized out.)
724 uint32_t infoIndex
= info
[i
].mGpu2
? 1 : 0;
725 if (adapterInfoFailed
[infoIndex
]) {
729 // Do the operating system check first, no point in getting the driver
730 // info if we won't need to use it.
731 if (!MatchingOperatingSystems(info
[i
].mOperatingSystem
, os
)) {
735 if (info
[i
].mOperatingSystemVersion
&& info
[i
].mOperatingSystemVersion
!= OperatingSystemVersion()) {
739 if (!info
[i
].mAdapterVendor
.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll
), nsCaseInsensitiveStringComparator()) &&
740 !info
[i
].mAdapterVendor
.Equals(adapterVendorID
[infoIndex
], nsCaseInsensitiveStringComparator())) {
744 if (info
[i
].mDevices
!= GfxDriverInfo::allDevices
&& info
[i
].mDevices
->Length()) {
745 bool deviceMatches
= false;
746 for (uint32_t j
= 0; j
< info
[i
].mDevices
->Length(); j
++) {
747 if ((*info
[i
].mDevices
)[j
].Equals(adapterDeviceID
[infoIndex
], nsCaseInsensitiveStringComparator())) {
748 deviceMatches
= true;
753 if (!deviceMatches
) {
760 if (!info
[i
].mHardware
.IsEmpty() && !info
[i
].mHardware
.Equals(Hardware())) {
763 if (!info
[i
].mModel
.IsEmpty() && !info
[i
].mModel
.Equals(Model())) {
766 if (!info
[i
].mProduct
.IsEmpty() && !info
[i
].mProduct
.Equals(Product())) {
769 if (!info
[i
].mManufacturer
.IsEmpty() && !info
[i
].mManufacturer
.Equals(Manufacturer())) {
773 #if defined(XP_WIN) || defined(ANDROID)
774 switch (info
[i
].mComparisonOp
) {
775 case DRIVER_LESS_THAN
:
776 match
= driverVersion
[infoIndex
] < info
[i
].mDriverVersion
;
778 case DRIVER_BUILD_ID_LESS_THAN
:
779 match
= (driverVersion
[infoIndex
] & 0xFFFF) < info
[i
].mDriverVersion
;
781 case DRIVER_LESS_THAN_OR_EQUAL
:
782 match
= driverVersion
[infoIndex
] <= info
[i
].mDriverVersion
;
784 case DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL
:
785 match
= (driverVersion
[infoIndex
] & 0xFFFF) <= info
[i
].mDriverVersion
;
787 case DRIVER_GREATER_THAN
:
788 match
= driverVersion
[infoIndex
] > info
[i
].mDriverVersion
;
790 case DRIVER_GREATER_THAN_OR_EQUAL
:
791 match
= driverVersion
[infoIndex
] >= info
[i
].mDriverVersion
;
794 match
= driverVersion
[infoIndex
] == info
[i
].mDriverVersion
;
796 case DRIVER_NOT_EQUAL
:
797 match
= driverVersion
[infoIndex
] != info
[i
].mDriverVersion
;
799 case DRIVER_BETWEEN_EXCLUSIVE
:
800 match
= driverVersion
[infoIndex
] > info
[i
].mDriverVersion
&& driverVersion
[infoIndex
] < info
[i
].mDriverVersionMax
;
802 case DRIVER_BETWEEN_INCLUSIVE
:
803 match
= driverVersion
[infoIndex
] >= info
[i
].mDriverVersion
&& driverVersion
[infoIndex
] <= info
[i
].mDriverVersionMax
;
805 case DRIVER_BETWEEN_INCLUSIVE_START
:
806 match
= driverVersion
[infoIndex
] >= info
[i
].mDriverVersion
&& driverVersion
[infoIndex
] < info
[i
].mDriverVersionMax
;
808 case DRIVER_COMPARISON_IGNORED
:
809 // We don't have a comparison op, so we match everything.
813 NS_WARNING("Bogus op in GfxDriverInfo");
817 // We don't care what driver version it was. We only check OS version and if
818 // the device matches.
822 if (match
|| info
[i
].mDriverVersion
== GfxDriverInfo::allDriverVersions
) {
823 if (info
[i
].mFeature
== GfxDriverInfo::allFeatures
||
824 info
[i
].mFeature
== aFeature
)
826 status
= info
[i
].mFeatureStatus
;
827 if (!info
[i
].mRuleId
.IsEmpty()) {
828 aFailureId
= info
[i
].mRuleId
.get();
830 aFailureId
= "FEATURE_FAILURE_DL_BLACKLIST_NO_ID";
838 // As a very special case, we block D2D on machines with an NVidia 310M GPU
839 // as either the primary or secondary adapter. D2D is also blocked when the
840 // NV 310M is the primary adapter (using the standard blocklisting mechanism).
841 // If the primary GPU already matched something in the blocklist then we
842 // ignore this special rule. See bug 1008759.
843 if (status
== nsIGfxInfo::FEATURE_STATUS_UNKNOWN
&&
844 (aFeature
== nsIGfxInfo::FEATURE_DIRECT2D
)) {
845 if (!adapterInfoFailed
[1]) {
846 nsAString
&nvVendorID
= (nsAString
&)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA
);
847 const nsString nv310mDeviceId
= NS_LITERAL_STRING("0x0A70");
848 if (nvVendorID
.Equals(adapterVendorID
[1], nsCaseInsensitiveStringComparator()) &&
849 nv310mDeviceId
.Equals(adapterDeviceID
[1], nsCaseInsensitiveStringComparator())) {
850 status
= nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
851 aFailureId
= "FEATURE_FAILURE_D2D_NV310M_BLOCK";
856 // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object
857 // back to the Windows handler, so we must handle this here.
858 if (status
== FEATURE_BLOCKED_DRIVER_VERSION
) {
859 if (info
[i
].mSuggestedVersion
) {
860 aSuggestedVersion
.AppendPrintf("%s", info
[i
].mSuggestedVersion
);
861 } else if (info
[i
].mComparisonOp
== DRIVER_LESS_THAN
&&
862 info
[i
].mDriverVersion
!= GfxDriverInfo::allDriverVersions
)
864 aSuggestedVersion
.AppendPrintf("%lld.%lld.%lld.%lld",
865 (info
[i
].mDriverVersion
& 0xffff000000000000) >> 48,
866 (info
[i
].mDriverVersion
& 0x0000ffff00000000) >> 32,
867 (info
[i
].mDriverVersion
& 0x00000000ffff0000) >> 16,
868 (info
[i
].mDriverVersion
& 0x000000000000ffff));
877 GfxInfoBase::SetFeatureStatus(const nsTArray
<dom::GfxInfoFeatureStatus
>& aFS
)
879 MOZ_ASSERT(!mFeatureStatus
);
880 mFeatureStatus
= new nsTArray
<dom::GfxInfoFeatureStatus
>(aFS
);
884 GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature
,
886 nsAString
& aSuggestedVersion
,
887 const nsTArray
<GfxDriverInfo
>& aDriverInfo
,
888 nsACString
& aFailureId
,
889 OperatingSystem
* aOS
/* = nullptr */)
892 gfxWarning() << "Invalid feature <= 0";
896 if (*aStatus
!= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
) {
897 // Terminate now with the status determined by the derived type (OS-specific
902 if (mShutdownOccurred
) {
903 // This is futile; we've already commenced shutdown and our blocklists have
904 // been deleted. We may want to look into resurrecting the blocklist instead
905 // but for now, just don't even go there.
909 // If an operating system was provided by the derived GetFeatureStatusImpl,
910 // grab it here. Otherwise, the OS is unknown.
911 OperatingSystem os
= (aOS
? *aOS
: OperatingSystem::Unknown
);
913 nsAutoString adapterVendorID
;
914 nsAutoString adapterDeviceID
;
915 nsAutoString adapterDriverVersionString
;
916 if (NS_FAILED(GetAdapterVendorID(adapterVendorID
)) ||
917 NS_FAILED(GetAdapterDeviceID(adapterDeviceID
)) ||
918 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString
)))
920 aFailureId
= "FEATURE_FAILURE_CANT_RESOLVE_ADAPTER";
921 *aStatus
= FEATURE_BLOCKED_DEVICE
;
925 // Check if the device is blocked from the downloaded blocklist. If not, check
926 // the static list after that. This order is used so that we can later escape
927 // out of static blocks (i.e. if we were wrong or something was patched, we
928 // can back out our static block without doing a release).
930 if (aDriverInfo
.Length()) {
931 status
= FindBlocklistedDeviceInList(aDriverInfo
, aSuggestedVersion
, aFeature
, aFailureId
, os
);
934 mDriverInfo
= new nsTArray
<GfxDriverInfo
>();
936 status
= FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion
, aFeature
, aFailureId
, os
);
939 // It's now done being processed. It's safe to set the status to STATUS_OK.
940 if (status
== nsIGfxInfo::FEATURE_STATUS_UNKNOWN
) {
941 *aStatus
= nsIGfxInfo::FEATURE_STATUS_OK
;
950 GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature
,
954 if (GetPrefValueForDriverVersion(version
)) {
955 aVersion
= NS_ConvertASCIItoUTF16(version
);
960 nsCString discardFailureId
;
961 nsTArray
<GfxDriverInfo
> driverInfo
;
962 return GetFeatureStatusImpl(aFeature
, &status
, aVersion
, driverInfo
, discardFailureId
);
967 GfxInfoBase::GetWebGLParameter(const nsAString
& aParam
,
970 return GfxInfoWebGL::GetWebGLParameter(aParam
, aResult
);
974 GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray
<GfxDriverInfo
>& aDriverInfo
)
976 int32_t features
[] = {
977 nsIGfxInfo::FEATURE_DIRECT2D
,
978 nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
,
979 nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
,
980 nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
,
981 nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
,
982 nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
,
983 nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING
,
984 nsIGfxInfo::FEATURE_OPENGL_LAYERS
,
985 nsIGfxInfo::FEATURE_WEBGL_OPENGL
,
986 nsIGfxInfo::FEATURE_WEBGL_ANGLE
,
987 nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE
,
988 nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE
,
989 nsIGfxInfo::FEATURE_WEBGL_MSAA
,
990 nsIGfxInfo::FEATURE_STAGEFRIGHT
,
991 nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION
,
992 nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION
,
993 nsIGfxInfo::FEATURE_WEBGL2
,
994 nsIGfxInfo::FEATURE_ADVANCED_LAYERS
,
995 nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX
,
999 // For every feature we know about, we evaluate whether this blacklist has a
1000 // non-STATUS_OK status. If it does, we set the pref we evaluate in
1001 // GetFeatureStatus above, so we don't need to hold on to this blacklist
1002 // anywhere permanent.
1004 while (features
[i
]) {
1006 nsCString failureId
;
1007 nsAutoString suggestedVersion
;
1008 if (NS_SUCCEEDED(GetFeatureStatusImpl(features
[i
], &status
,
1014 case nsIGfxInfo::FEATURE_STATUS_OK
:
1015 RemovePrefForFeature(features
[i
]);
1018 case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
:
1019 if (!suggestedVersion
.IsEmpty()) {
1020 SetPrefValueForDriverVersion(suggestedVersion
);
1022 RemovePrefForDriverVersion();
1026 case nsIGfxInfo::FEATURE_BLOCKED_MISMATCHED_VERSION
:
1027 case nsIGfxInfo::FEATURE_BLOCKED_DEVICE
:
1028 case nsIGfxInfo::FEATURE_DISCOURAGED
:
1029 case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION
:
1030 SetPrefValueForFeature(features
[i
], status
, failureId
);
1039 NS_IMETHODIMP_(void)
1040 GfxInfoBase::LogFailure(const nsACString
&failure
)
1042 // gfxCriticalError has a mutex lock of its own, so we may not actually
1043 // need this lock. ::GetFailures() accesses the data but the LogForwarder
1044 // will not return the copy of the logs unless it can get the same lock
1045 // that gfxCriticalError uses. Still, that is so much of an implementation
1046 // detail that it's nicer to just add an extra lock here and in ::GetFailures()
1047 MutexAutoLock
lock(mMutex
);
1049 // By default, gfxCriticalError asserts; make it not assert in this case.
1050 gfxCriticalError(CriticalLog::DefaultOptions(false)) << "(LF) " << failure
.BeginReading();
1053 /* XPConnect method of returning arrays is very ugly. Would not recommend. */
1054 NS_IMETHODIMP
GfxInfoBase::GetFailures(uint32_t* failureCount
,
1058 MutexAutoLock
lock(mMutex
);
1060 NS_ENSURE_ARG_POINTER(failureCount
);
1061 NS_ENSURE_ARG_POINTER(failures
);
1063 *failures
= nullptr;
1066 // indices is "allowed" to be null, the caller may not care about them,
1067 // although calling from JS doesn't seem to get us there.
1068 if (indices
) *indices
= nullptr;
1070 LogForwarder
* logForwarder
= Factory::GetLogForwarder();
1071 if (!logForwarder
) {
1072 return NS_ERROR_UNEXPECTED
;
1075 // There are two stirng copies in this method, starting with this one. We are
1076 // assuming this is not a big deal, as the size of the array should be small
1077 // and the strings in it should be small as well (the error messages in the
1078 // code.) The second copy happens with the Clone() calls. Technically,
1079 // we don't need the mutex lock after the StringVectorCopy() call.
1080 LoggingRecord loggedStrings
= logForwarder
->LoggingRecordCopy();
1081 *failureCount
= loggedStrings
.size();
1083 if (*failureCount
!= 0) {
1084 *failures
= (char**)moz_xmalloc(*failureCount
* sizeof(char*));
1086 return NS_ERROR_OUT_OF_MEMORY
;
1089 *indices
= (int32_t*)moz_xmalloc(*failureCount
* sizeof(int32_t));
1092 *failures
= nullptr;
1093 return NS_ERROR_OUT_OF_MEMORY
;
1097 /* copy over the failure messages into the array we just allocated */
1098 LoggingRecord::const_iterator it
;
1100 for(it
= loggedStrings
.begin() ; it
!= loggedStrings
.end(); ++it
, i
++) {
1101 (*failures
)[i
] = (char*)nsMemory::Clone(Get
<1>(*it
).c_str(), Get
<1>(*it
).size() + 1);
1102 if (indices
) (*indices
)[i
] = Get
<0>(*it
);
1104 if (!(*failures
)[i
]) {
1105 /* <sarcasm> I'm too afraid to use an inline function... </sarcasm> */
1106 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i
, (*failures
));
1108 return NS_ERROR_OUT_OF_MEMORY
;
1116 nsTArray
<GfxInfoCollectorBase
*> *sCollectors
;
1122 sCollectors
= new nsTArray
<GfxInfoCollectorBase
*>;
1125 nsresult
GfxInfoBase::GetInfo(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aResult
)
1128 InfoObject
obj(aCx
);
1130 for (uint32_t i
= 0; i
< sCollectors
->Length(); i
++) {
1131 (*sCollectors
)[i
]->GetInfo(obj
);
1134 // Some example property definitions
1135 // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
1136 // obj.DefineProperty("renderer", mRendererIDsString);
1137 // obj.DefineProperty("five", 5);
1140 return NS_ERROR_FAILURE
;
1143 aResult
.setObject(*obj
.mObj
);
1147 nsAutoCString gBaseAppVersion
;
1150 GfxInfoBase::GetApplicationVersion()
1152 static bool versionInitialized
= false;
1153 if (!versionInitialized
) {
1154 // If we fail to get the version, we will not try again.
1155 versionInitialized
= true;
1157 // Get the version from xpcom/system/nsIXULAppInfo.idl
1158 nsCOMPtr
<nsIXULAppInfo
> app
= do_GetService("@mozilla.org/xre/app-info;1");
1160 app
->GetVersion(gBaseAppVersion
);
1163 return gBaseAppVersion
;
1167 GfxInfoBase::AddCollector(GfxInfoCollectorBase
* collector
)
1170 sCollectors
->AppendElement(collector
);
1174 GfxInfoBase::RemoveCollector(GfxInfoCollectorBase
* collector
)
1177 for (uint32_t i
= 0; i
< sCollectors
->Length(); i
++) {
1178 if ((*sCollectors
)[i
] == collector
) {
1179 sCollectors
->RemoveElementAt(i
);
1183 if (sCollectors
->IsEmpty()) {
1185 sCollectors
= nullptr;
1190 GfxInfoBase::GetMonitors(JSContext
* aCx
, JS::MutableHandleValue aResult
)
1192 JS::Rooted
<JSObject
*> array(aCx
, JS_NewArrayObject(aCx
, 0));
1194 nsresult rv
= FindMonitors(aCx
, array
);
1195 if (NS_FAILED(rv
)) {
1199 aResult
.setObject(*array
);
1204 GetLayersBackendName(layers::LayersBackend aBackend
)
1207 case layers::LayersBackend::LAYERS_NONE
:
1209 case layers::LayersBackend::LAYERS_OPENGL
:
1211 case layers::LayersBackend::LAYERS_D3D11
:
1213 case layers::LayersBackend::LAYERS_CLIENT
:
1215 case layers::LayersBackend::LAYERS_WR
:
1217 case layers::LayersBackend::LAYERS_BASIC
:
1220 MOZ_ASSERT_UNREACHABLE("unknown layers backend");
1226 SetJSPropertyString(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
1227 const char* aProp
, const char* aString
)
1229 JS::Rooted
<JSString
*> str(aCx
, JS_NewStringCopyZ(aCx
, aString
));
1234 JS::Rooted
<JS::Value
> val(aCx
, JS::StringValue(str
));
1235 return JS_SetProperty(aCx
, aObj
, aProp
, val
);
1238 template <typename T
>
1240 AppendJSElement(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
, const T
& aValue
)
1243 if (!JS_GetArrayLength(aCx
, aObj
, &index
)) {
1246 return JS_SetElement(aCx
, aObj
, index
, aValue
);
1250 GfxInfoBase::GetFeatures(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aOut
)
1252 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1254 return NS_ERROR_OUT_OF_MEMORY
;
1256 aOut
.setObject(*obj
);
1258 layers::LayersBackend backend
= gfxPlatform::Initialized()
1259 ? gfxPlatform::GetPlatform()->GetCompositorBackend()
1260 : layers::LayersBackend::LAYERS_NONE
;
1261 const char* backendName
= GetLayersBackendName(backend
);
1262 SetJSPropertyString(aCx
, obj
, "compositor", backendName
);
1264 // If graphics isn't initialized yet, just stop now.
1265 if (!gfxPlatform::Initialized()) {
1269 DescribeFeatures(aCx
, obj
);
1273 nsresult
GfxInfoBase::GetFeatureLog(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aOut
)
1275 JS::Rooted
<JSObject
*> containerObj(aCx
, JS_NewPlainObject(aCx
));
1276 if (!containerObj
) {
1277 return NS_ERROR_OUT_OF_MEMORY
;
1279 aOut
.setObject(*containerObj
);
1281 JS::Rooted
<JSObject
*> featureArray(aCx
, JS_NewArrayObject(aCx
, 0));
1282 if (!featureArray
) {
1283 return NS_ERROR_OUT_OF_MEMORY
;
1286 // Collect features.
1287 gfxConfig::ForEachFeature([&](const char* aName
,
1288 const char* aDescription
,
1289 FeatureState
& aFeature
) -> void {
1290 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1294 if (!SetJSPropertyString(aCx
, obj
, "name", aName
) ||
1295 !SetJSPropertyString(aCx
, obj
, "description", aDescription
) ||
1296 !SetJSPropertyString(aCx
, obj
, "status", FeatureStatusToString(aFeature
.GetValue())))
1301 JS::Rooted
<JS::Value
> log(aCx
);
1302 if (!BuildFeatureStateLog(aCx
, aFeature
, &log
)) {
1305 if (!JS_SetProperty(aCx
, obj
, "log", log
)) {
1309 if (!AppendJSElement(aCx
, featureArray
, obj
)) {
1314 JS::Rooted
<JSObject
*> fallbackArray(aCx
, JS_NewArrayObject(aCx
, 0));
1315 if (!fallbackArray
) {
1316 return NS_ERROR_OUT_OF_MEMORY
;
1319 // Collect fallbacks.
1320 gfxConfig::ForEachFallback([&](const char* aName
, const char* aMessage
) -> void {
1321 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1326 if (!SetJSPropertyString(aCx
, obj
, "name", aName
) ||
1327 !SetJSPropertyString(aCx
, obj
, "message", aMessage
))
1332 if (!AppendJSElement(aCx
, fallbackArray
, obj
)) {
1337 JS::Rooted
<JS::Value
> val(aCx
);
1339 val
= JS::ObjectValue(*featureArray
);
1340 JS_SetProperty(aCx
, containerObj
, "features", val
);
1342 val
= JS::ObjectValue(*fallbackArray
);
1343 JS_SetProperty(aCx
, containerObj
, "fallbacks", val
);
1349 GfxInfoBase::BuildFeatureStateLog(JSContext
* aCx
, const FeatureState
& aFeature
,
1350 JS::MutableHandle
<JS::Value
> aOut
)
1352 JS::Rooted
<JSObject
*> log(aCx
, JS_NewArrayObject(aCx
, 0));
1356 aOut
.setObject(*log
);
1358 aFeature
.ForEachStatusChange([&](const char* aType
,
1359 FeatureStatus aStatus
,
1360 const char* aMessage
) -> void {
1361 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1366 if (!SetJSPropertyString(aCx
, obj
, "type", aType
) ||
1367 !SetJSPropertyString(aCx
, obj
, "status", FeatureStatusToString(aStatus
)) ||
1368 (aMessage
&& !SetJSPropertyString(aCx
, obj
, "message", aMessage
)))
1373 if (!AppendJSElement(aCx
, log
, obj
)) {
1382 GfxInfoBase::DescribeFeatures(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
)
1384 JS::Rooted
<JSObject
*> obj(aCx
);
1386 gfx::FeatureStatus gpuProcess
= gfxConfig::GetValue(Feature::GPU_PROCESS
);
1387 InitFeatureObject(aCx
, aObj
, "gpuProcess", FEATURE_GPU_PROCESS
, Some(gpuProcess
), &obj
);
1389 // Only include AL if the platform attempted to use it.
1390 gfx::FeatureStatus advancedLayers
= gfxConfig::GetValue(Feature::ADVANCED_LAYERS
);
1391 if (advancedLayers
!= FeatureStatus::Unused
) {
1392 InitFeatureObject(aCx
, aObj
, "advancedLayers", FEATURE_ADVANCED_LAYERS
,
1393 Some(advancedLayers
), &obj
);
1395 if (gfxConfig::UseFallback(Fallback::NO_CONSTANT_BUFFER_OFFSETTING
)) {
1396 JS::Rooted
<JS::Value
> trueVal(aCx
, JS::BooleanValue(true));
1397 JS_SetProperty(aCx
, obj
, "noConstantBufferOffsetting", trueVal
);
1403 GfxInfoBase::InitFeatureObject(JSContext
* aCx
,
1404 JS::Handle
<JSObject
*> aContainer
,
1407 const Maybe
<mozilla::gfx::FeatureStatus
>& aFeatureStatus
,
1408 JS::MutableHandle
<JSObject
*> aOutObj
)
1410 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1415 nsCString failureId
= NS_LITERAL_CSTRING("OK");
1417 if (!NS_SUCCEEDED(GetFeatureStatus(aFeature
, failureId
, &unused
))) {
1422 if (aFeatureStatus
) {
1423 const char* status
= FeatureStatusToString(aFeatureStatus
.value());
1425 JS::Rooted
<JSString
*> str(aCx
, JS_NewStringCopyZ(aCx
, status
));
1426 JS::Rooted
<JS::Value
> val(aCx
, JS::StringValue(str
));
1427 JS_SetProperty(aCx
, obj
, "status", val
);
1430 // Add the feature object to the container.
1432 JS::Rooted
<JS::Value
> val(aCx
, JS::ObjectValue(*obj
));
1433 JS_SetProperty(aCx
, aContainer
, aName
, val
);
1441 GfxInfoBase::GetActiveCrashGuards(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aOut
)
1443 JS::Rooted
<JSObject
*> array(aCx
, JS_NewArrayObject(aCx
, 0));
1445 return NS_ERROR_OUT_OF_MEMORY
;
1447 aOut
.setObject(*array
);
1449 DriverCrashGuard::ForEachActiveCrashGuard([&](const char* aName
,
1450 const char* aPrefName
) -> void {
1451 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1455 if (!SetJSPropertyString(aCx
, obj
, "type", aName
)) {
1458 if (!SetJSPropertyString(aCx
, obj
, "prefName", aPrefName
)) {
1461 if (!AppendJSElement(aCx
, array
, obj
)) {
1470 GfxInfoBase::GetWebRenderEnabled(bool* aWebRenderEnabled
)
1472 *aWebRenderEnabled
= gfxVars::UseWebRender();
1477 GfxInfoBase::GetOffMainThreadPaintEnabled(bool* aOffMainThreadPaintEnabled
)
1479 *aOffMainThreadPaintEnabled
= gfxConfig::IsEnabled(Feature::OMTP
);
1484 GfxInfoBase::GetIsHeadless(bool* aIsHeadless
)
1486 *aIsHeadless
= gfxPlatform::IsHeadless();
1491 GfxInfoBase::GetContentBackend(nsAString
& aContentBackend
)
1493 BackendType backend
= gfxPlatform::GetPlatform()->GetDefaultContentBackend();
1497 case BackendType::DIRECT2D1_1
: {
1498 outStr
.AppendPrintf("Direct2D 1.1");
1501 case BackendType::SKIA
: {
1502 outStr
.AppendPrintf("Skia");
1505 case BackendType::CAIRO
: {
1506 outStr
.AppendPrintf("Cairo");
1510 return NS_ERROR_FAILURE
;
1513 aContentBackend
.Assign(outStr
);
1518 GfxInfoBase::GetUsingGPUProcess(bool *aOutValue
)
1520 GPUProcessManager
* gpu
= GPUProcessManager::Get();
1522 // Not supported in content processes.
1523 return NS_ERROR_FAILURE
;
1526 *aOutValue
= !!gpu
->GetGPUChild();
1531 GfxInfoBase::ControlGPUProcessForXPCShell(bool aEnable
, bool *_retval
)
1533 gfxPlatform::GetPlatform();
1535 GPUProcessManager
* gpm
= GPUProcessManager::Get();
1537 if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS
)) {
1538 gfxConfig::UserForceEnable(Feature::GPU_PROCESS
, "xpcshell-test");
1540 gpm
->LaunchGPUProcess();
1541 gpm
->EnsureGPUReady();
1550 GfxInfoCollectorBase::GfxInfoCollectorBase()
1552 GfxInfoBase::AddCollector(this);
1555 GfxInfoCollectorBase::~GfxInfoCollectorBase()
1557 GfxInfoBase::RemoveCollector(this);