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"
16 #include "nsAutoPtr.h"
18 #include "nsUnicharUtils.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 "mozilla/Preferences.h"
30 #include "mozilla/dom/ContentChild.h"
31 #include "mozilla/gfx/2D.h"
32 #include "mozilla/gfx/Logging.h"
34 using namespace mozilla::widget
;
35 using namespace mozilla
;
36 using mozilla::MutexAutoLock
;
38 nsTArray
<GfxDriverInfo
>* GfxInfoBase::mDriverInfo
;
39 bool GfxInfoBase::mDriverInfoObserverInitialized
;
41 // Observes for shutdown so that the child GfxDriverInfo list is freed.
42 class ShutdownObserver
: public nsIObserver
44 virtual ~ShutdownObserver() {}
51 NS_IMETHOD
Observe(nsISupports
*subject
, const char *aTopic
,
52 const char16_t
*aData
) override
54 MOZ_ASSERT(strcmp(aTopic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
) == 0);
56 delete GfxInfoBase::mDriverInfo
;
57 GfxInfoBase::mDriverInfo
= nullptr;
59 for (uint32_t i
= 0; i
< DeviceFamilyMax
; i
++)
60 delete GfxDriverInfo::mDeviceFamilies
[i
];
62 for (uint32_t i
= 0; i
< DeviceVendorMax
; i
++)
63 delete GfxDriverInfo::mDeviceVendors
[i
];
69 NS_IMPL_ISUPPORTS(ShutdownObserver
, nsIObserver
)
71 void InitGfxDriverInfoShutdownObserver()
73 if (GfxInfoBase::mDriverInfoObserverInitialized
)
76 GfxInfoBase::mDriverInfoObserverInitialized
= true;
78 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
79 if (!observerService
) {
80 NS_WARNING("Could not get observer service!");
84 ShutdownObserver
*obs
= new ShutdownObserver();
85 observerService
->AddObserver(obs
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
88 using namespace mozilla::widget
;
89 using namespace mozilla::gfx
;
90 using namespace mozilla
;
93 NS_IMPL_ISUPPORTS(GfxInfoBase
, nsIGfxInfo
, nsIGfxInfo2
, nsIObserver
, nsISupportsWeakReference
)
95 NS_IMPL_ISUPPORTS(GfxInfoBase
, nsIGfxInfo
, nsIObserver
, nsISupportsWeakReference
)
98 #define BLACKLIST_PREF_BRANCH "gfx.blacklist."
99 #define SUGGESTED_VERSION_PREF BLACKLIST_PREF_BRANCH "suggested-driver-version"
100 #define BLACKLIST_ENTRY_TAG_NAME "gfxBlacklistEntry"
103 GetPrefNameForFeature(int32_t aFeature
)
105 const char* name
= nullptr;
107 case nsIGfxInfo::FEATURE_DIRECT2D
:
108 name
= BLACKLIST_PREF_BRANCH
"direct2d";
110 case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
:
111 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d9";
113 case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
:
114 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d10";
116 case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
:
117 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d10-1";
119 case nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
:
120 name
= BLACKLIST_PREF_BRANCH
"layers.direct3d11";
122 case nsIGfxInfo::FEATURE_DXVA
:
123 name
= BLACKLIST_PREF_BRANCH
"dxva";
125 case nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
:
126 name
= BLACKLIST_PREF_BRANCH
"direct3d11angle";
128 case nsIGfxInfo::FEATURE_OPENGL_LAYERS
:
129 name
= BLACKLIST_PREF_BRANCH
"layers.opengl";
131 case nsIGfxInfo::FEATURE_WEBGL_OPENGL
:
132 name
= BLACKLIST_PREF_BRANCH
"webgl.opengl";
134 case nsIGfxInfo::FEATURE_WEBGL_ANGLE
:
135 name
= BLACKLIST_PREF_BRANCH
"webgl.angle";
137 case nsIGfxInfo::FEATURE_WEBGL_MSAA
:
138 name
= BLACKLIST_PREF_BRANCH
"webgl.msaa";
140 case nsIGfxInfo::FEATURE_STAGEFRIGHT
:
141 name
= BLACKLIST_PREF_BRANCH
"stagefright";
150 // Returns the value of the pref for the relevant feature in aValue.
151 // If the pref doesn't exist, aValue is not touched, and returns false.
153 GetPrefValueForFeature(int32_t aFeature
, int32_t& aValue
)
155 const char *prefname
= GetPrefNameForFeature(aFeature
);
160 return NS_SUCCEEDED(Preferences::GetInt(prefname
, &aValue
));
164 SetPrefValueForFeature(int32_t aFeature
, int32_t aValue
)
166 const char *prefname
= GetPrefNameForFeature(aFeature
);
170 Preferences::SetInt(prefname
, aValue
);
174 RemovePrefForFeature(int32_t aFeature
)
176 const char *prefname
= GetPrefNameForFeature(aFeature
);
180 Preferences::ClearUser(prefname
);
184 GetPrefValueForDriverVersion(nsCString
& aVersion
)
186 return NS_SUCCEEDED(Preferences::GetCString(SUGGESTED_VERSION_PREF
,
191 SetPrefValueForDriverVersion(const nsAString
& aVersion
)
193 Preferences::SetString(SUGGESTED_VERSION_PREF
, aVersion
);
197 RemovePrefForDriverVersion()
199 Preferences::ClearUser(SUGGESTED_VERSION_PREF
);
202 // <foo>Hello</foo> - "Hello" is stored as a child text node of the foo node.
204 BlacklistNodeToTextValue(nsIDOMNode
*aBlacklistNode
, nsAString
& aValue
)
207 if (NS_FAILED(aBlacklistNode
->GetTextContent(value
)))
210 value
.Trim(" \t\r\n");
216 static OperatingSystem
217 BlacklistOSToOperatingSystem(const nsAString
& os
)
219 if (os
.EqualsLiteral("WINNT 5.1"))
220 return DRIVER_OS_WINDOWS_XP
;
221 else if (os
.EqualsLiteral("WINNT 5.2"))
222 return DRIVER_OS_WINDOWS_SERVER_2003
;
223 else if (os
.EqualsLiteral("WINNT 6.0"))
224 return DRIVER_OS_WINDOWS_VISTA
;
225 else if (os
.EqualsLiteral("WINNT 6.1"))
226 return DRIVER_OS_WINDOWS_7
;
227 else if (os
.EqualsLiteral("WINNT 6.2"))
228 return DRIVER_OS_WINDOWS_8
;
229 else if (os
.EqualsLiteral("WINNT 6.3"))
230 return DRIVER_OS_WINDOWS_8_1
;
231 else if (os
.EqualsLiteral("Linux"))
232 return DRIVER_OS_LINUX
;
233 else if (os
.EqualsLiteral("Darwin 9"))
234 return DRIVER_OS_OS_X_10_5
;
235 else if (os
.EqualsLiteral("Darwin 10"))
236 return DRIVER_OS_OS_X_10_6
;
237 else if (os
.EqualsLiteral("Darwin 11"))
238 return DRIVER_OS_OS_X_10_7
;
239 else if (os
.EqualsLiteral("Darwin 12"))
240 return DRIVER_OS_OS_X_10_8
;
241 else if (os
.EqualsLiteral("Darwin 13"))
242 return DRIVER_OS_OS_X_10_9
;
243 else if (os
.EqualsLiteral("Darwin 14"))
244 return DRIVER_OS_OS_X_10_10
;
245 else if (os
.EqualsLiteral("Android"))
246 return DRIVER_OS_ANDROID
;
247 else if (os
.EqualsLiteral("All"))
248 return DRIVER_OS_ALL
;
250 return DRIVER_OS_UNKNOWN
;
253 static GfxDeviceFamily
*
254 BlacklistDevicesToDeviceFamily(nsIDOMHTMLCollection
* aDevices
)
257 if (NS_FAILED(aDevices
->GetLength(&length
)))
260 // For each <device>, get its device ID, and return a freshly-allocated
261 // GfxDeviceFamily with the contents of that array.
262 GfxDeviceFamily
* deviceIds
= new GfxDeviceFamily
;
264 for (uint32_t i
= 0; i
< length
; ++i
) {
265 nsCOMPtr
<nsIDOMNode
> node
;
266 if (NS_FAILED(aDevices
->Item(i
, getter_AddRefs(node
))) || !node
)
269 nsAutoString deviceValue
;
270 if (!BlacklistNodeToTextValue(node
, deviceValue
))
273 deviceIds
->AppendElement(deviceValue
);
280 BlacklistFeatureToGfxFeature(const nsAString
& aFeature
)
282 if (aFeature
.EqualsLiteral("DIRECT2D"))
283 return nsIGfxInfo::FEATURE_DIRECT2D
;
284 else if (aFeature
.EqualsLiteral("DIRECT3D_9_LAYERS"))
285 return nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
;
286 else if (aFeature
.EqualsLiteral("DIRECT3D_10_LAYERS"))
287 return nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
;
288 else if (aFeature
.EqualsLiteral("DIRECT3D_10_1_LAYERS"))
289 return nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
;
290 else if (aFeature
.EqualsLiteral("DIRECT3D_11_LAYERS"))
291 return nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
;
292 else if (aFeature
.EqualsLiteral("DIRECT3D_11_ANGLE"))
293 return nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
;
294 else if (aFeature
.EqualsLiteral("DXVA"))
295 return nsIGfxInfo::FEATURE_DXVA
;
296 else if (aFeature
.EqualsLiteral("OPENGL_LAYERS"))
297 return nsIGfxInfo::FEATURE_OPENGL_LAYERS
;
298 else if (aFeature
.EqualsLiteral("WEBGL_OPENGL"))
299 return nsIGfxInfo::FEATURE_WEBGL_OPENGL
;
300 else if (aFeature
.EqualsLiteral("WEBGL_ANGLE"))
301 return nsIGfxInfo::FEATURE_WEBGL_ANGLE
;
302 else if (aFeature
.EqualsLiteral("WEBGL_MSAA"))
303 return nsIGfxInfo::FEATURE_WEBGL_MSAA
;
304 else if (aFeature
.EqualsLiteral("STAGEFRIGHT"))
305 return nsIGfxInfo::FEATURE_STAGEFRIGHT
;
310 BlacklistFeatureStatusToGfxFeatureStatus(const nsAString
& aStatus
)
312 if (aStatus
.EqualsLiteral("STATUS_OK"))
313 return nsIGfxInfo::FEATURE_STATUS_OK
;
314 else if (aStatus
.EqualsLiteral("BLOCKED_DRIVER_VERSION"))
315 return nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
;
316 else if (aStatus
.EqualsLiteral("BLOCKED_DEVICE"))
317 return nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
318 else if (aStatus
.EqualsLiteral("DISCOURAGED"))
319 return nsIGfxInfo::FEATURE_DISCOURAGED
;
320 else if (aStatus
.EqualsLiteral("BLOCKED_OS_VERSION"))
321 return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION
;
323 // Do not allow it to set STATUS_UNKNOWN.
325 return nsIGfxInfo::FEATURE_STATUS_OK
;
328 static VersionComparisonOp
329 BlacklistComparatorToComparisonOp(const nsAString
& op
)
331 if (op
.EqualsLiteral("LESS_THAN"))
332 return DRIVER_LESS_THAN
;
333 else if (op
.EqualsLiteral("LESS_THAN_OR_EQUAL"))
334 return DRIVER_LESS_THAN_OR_EQUAL
;
335 else if (op
.EqualsLiteral("GREATER_THAN"))
336 return DRIVER_GREATER_THAN
;
337 else if (op
.EqualsLiteral("GREATER_THAN_OR_EQUAL"))
338 return DRIVER_GREATER_THAN_OR_EQUAL
;
339 else if (op
.EqualsLiteral("EQUAL"))
341 else if (op
.EqualsLiteral("NOT_EQUAL"))
342 return DRIVER_NOT_EQUAL
;
343 else if (op
.EqualsLiteral("BETWEEN_EXCLUSIVE"))
344 return DRIVER_BETWEEN_EXCLUSIVE
;
345 else if (op
.EqualsLiteral("BETWEEN_INCLUSIVE"))
346 return DRIVER_BETWEEN_INCLUSIVE
;
347 else if (op
.EqualsLiteral("BETWEEN_INCLUSIVE_START"))
348 return DRIVER_BETWEEN_INCLUSIVE_START
;
350 return DRIVER_COMPARISON_IGNORED
;
353 // Arbitrarily returns the first |tagname| child of |element|.
355 BlacklistNodeGetChildByName(nsIDOMElement
*element
,
356 const nsAString
& tagname
,
357 nsIDOMNode
** firstchild
)
359 nsCOMPtr
<nsIDOMHTMLCollection
> nodelist
;
360 if (NS_FAILED(element
->GetElementsByTagName(tagname
,
361 getter_AddRefs(nodelist
))) ||
366 nsCOMPtr
<nsIDOMNode
> node
;
367 if (NS_FAILED(nodelist
->Item(0, getter_AddRefs(node
))) || !node
)
370 node
.forget(firstchild
);
378 <vendor>0x8086</vendor>
380 <device>0x2582</device>
381 <device>0x2782</device>
383 <feature> DIRECT3D_10_LAYERS </feature>
384 <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
385 <driverVersion> 8.52.322.2202 </driverVersion>
386 <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
391 BlacklistEntryToDriverInfo(nsIDOMNode
* aBlacklistEntry
,
392 GfxDriverInfo
& aDriverInfo
)
394 nsAutoString nodename
;
395 if (NS_FAILED(aBlacklistEntry
->GetNodeName(nodename
)) ||
396 nodename
!= NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME
)) {
400 nsCOMPtr
<nsIDOMElement
> element
= do_QueryInterface(aBlacklistEntry
);
404 nsCOMPtr
<nsIDOMNode
> dataNode
;
405 nsAutoString dataValue
;
407 // <os>WINNT 6.0</os>
408 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("os"),
409 getter_AddRefs(dataNode
))) {
410 BlacklistNodeToTextValue(dataNode
, dataValue
);
411 aDriverInfo
.mOperatingSystem
= BlacklistOSToOperatingSystem(dataValue
);
414 // <osversion>14</osversion> currently only used for Android
415 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("osversion"),
416 getter_AddRefs(dataNode
))) {
417 BlacklistNodeToTextValue(dataNode
, dataValue
);
418 aDriverInfo
.mOperatingSystemVersion
= strtoul(NS_LossyConvertUTF16toASCII(dataValue
).get(),
422 // <vendor>0x8086</vendor>
423 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("vendor"),
424 getter_AddRefs(dataNode
))) {
425 BlacklistNodeToTextValue(dataNode
, dataValue
);
426 aDriverInfo
.mAdapterVendor
= dataValue
;
430 // <device>0x2582</device>
431 // <device>0x2782</device>
433 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("devices"),
434 getter_AddRefs(dataNode
))) {
435 nsCOMPtr
<nsIDOMElement
> devicesElement
= do_QueryInterface(dataNode
);
436 if (devicesElement
) {
438 // Get only the <device> nodes, because BlacklistDevicesToDeviceFamily
439 // assumes it is passed no other nodes.
440 nsCOMPtr
<nsIDOMHTMLCollection
> devices
;
441 if (NS_SUCCEEDED(devicesElement
->GetElementsByTagName(NS_LITERAL_STRING("device"),
442 getter_AddRefs(devices
)))) {
443 GfxDeviceFamily
* deviceIds
= BlacklistDevicesToDeviceFamily(devices
);
445 // Get GfxDriverInfo to adopt the devices array we created.
446 aDriverInfo
.mDeleteDevices
= true;
447 aDriverInfo
.mDevices
= deviceIds
;
453 // <feature> DIRECT3D_10_LAYERS </feature>
454 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("feature"),
455 getter_AddRefs(dataNode
))) {
456 BlacklistNodeToTextValue(dataNode
, dataValue
);
457 aDriverInfo
.mFeature
= BlacklistFeatureToGfxFeature(dataValue
);
460 // <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
461 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("featureStatus"),
462 getter_AddRefs(dataNode
))) {
463 BlacklistNodeToTextValue(dataNode
, dataValue
);
464 aDriverInfo
.mFeatureStatus
= BlacklistFeatureStatusToGfxFeatureStatus(dataValue
);
467 // <driverVersion> 8.52.322.2202 </driverVersion>
468 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("driverVersion"),
469 getter_AddRefs(dataNode
))) {
470 BlacklistNodeToTextValue(dataNode
, dataValue
);
472 if (ParseDriverVersion(dataValue
, &version
))
473 aDriverInfo
.mDriverVersion
= version
;
476 // <driverVersionComparator> LESS_THAN_OR_EQUAL </driverVersionComparator>
477 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("driverVersionComparator"),
478 getter_AddRefs(dataNode
))) {
479 BlacklistNodeToTextValue(dataNode
, dataValue
);
480 aDriverInfo
.mComparisonOp
= BlacklistComparatorToComparisonOp(dataValue
);
483 // <model>foo</model>
484 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("model"),
485 getter_AddRefs(dataNode
))) {
486 BlacklistNodeToTextValue(dataNode
, dataValue
);
487 aDriverInfo
.mModel
= dataValue
;
489 // <product>foo</product>
490 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("product"),
491 getter_AddRefs(dataNode
))) {
492 BlacklistNodeToTextValue(dataNode
, dataValue
);
493 aDriverInfo
.mProduct
= dataValue
;
495 // <manufacturer>foo</manufacturer>
496 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("manufacturer"),
497 getter_AddRefs(dataNode
))) {
498 BlacklistNodeToTextValue(dataNode
, dataValue
);
499 aDriverInfo
.mManufacturer
= dataValue
;
501 // <hardware>foo</hardware>
502 if (BlacklistNodeGetChildByName(element
, NS_LITERAL_STRING("hardware"),
503 getter_AddRefs(dataNode
))) {
504 BlacklistNodeToTextValue(dataNode
, dataValue
);
505 aDriverInfo
.mHardware
= dataValue
;
508 // We explicitly ignore unknown elements.
514 BlacklistEntriesToDriverInfo(nsIDOMHTMLCollection
* aBlacklistEntries
,
515 nsTArray
<GfxDriverInfo
>& aDriverInfo
)
518 if (NS_FAILED(aBlacklistEntries
->GetLength(&length
)))
522 aDriverInfo
.SetLength(length
);
523 for (uint32_t i
= 0; i
< length
; ++i
) {
524 nsCOMPtr
<nsIDOMNode
> blacklistEntry
;
525 if (NS_SUCCEEDED(aBlacklistEntries
->Item(i
,
526 getter_AddRefs(blacklistEntry
))) &&
529 if (BlacklistEntryToDriverInfo(blacklistEntry
, di
)) {
532 // Prevent di falling out of scope from destroying the devices.
533 di
.mDeleteDevices
= false;
539 GfxInfoBase::Observe(nsISupports
* aSubject
, const char* aTopic
,
540 const char16_t
* aData
)
542 if (strcmp(aTopic
, "blocklist-data-gfxItems") == 0) {
543 nsCOMPtr
<nsIDOMElement
> gfxItems
= do_QueryInterface(aSubject
);
545 nsCOMPtr
<nsIDOMHTMLCollection
> blacklistEntries
;
546 if (NS_SUCCEEDED(gfxItems
->
547 GetElementsByTagName(NS_LITERAL_STRING(BLACKLIST_ENTRY_TAG_NAME
),
548 getter_AddRefs(blacklistEntries
))) &&
551 nsTArray
<GfxDriverInfo
> driverInfo
;
552 BlacklistEntriesToDriverInfo(blacklistEntries
, driverInfo
);
553 EvaluateDownloadedBlacklist(driverInfo
);
561 GfxInfoBase::GfxInfoBase()
562 : mMutex("GfxInfoBase")
566 GfxInfoBase::~GfxInfoBase()
573 InitGfxDriverInfoShutdownObserver();
575 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
577 os
->AddObserver(this, "blocklist-data-gfxItems", true);
584 GfxInfoBase::GetFeatureStatus(int32_t aFeature
, int32_t* aStatus
)
586 if (GetPrefValueForFeature(aFeature
, *aStatus
))
589 if (XRE_GetProcessType() == GoannaProcessType_Content
) {
590 // Delegate to the parent process.
591 mozilla::dom::ContentChild
* cc
= mozilla::dom::ContentChild::GetSingleton();
593 cc
->SendGetGraphicsFeatureStatus(aFeature
, aStatus
, &success
);
594 return success
? NS_OK
: NS_ERROR_FAILURE
;
598 nsTArray
<GfxDriverInfo
> driverInfo
;
599 return GetFeatureStatusImpl(aFeature
, aStatus
, version
, driverInfo
);
603 GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray
<GfxDriverInfo
>& info
,
604 nsAString
& aSuggestedVersion
,
608 int32_t status
= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
;
611 for (; i
< info
.Length(); i
++) {
612 // XXX: it would be better not to do this everytime round the loop
613 nsAutoString adapterVendorID
;
614 nsAutoString adapterDeviceID
;
615 nsAutoString adapterDriverVersionString
;
617 if (NS_FAILED(GetAdapterVendorID2(adapterVendorID
)) ||
618 NS_FAILED(GetAdapterDeviceID2(adapterDeviceID
)) ||
619 NS_FAILED(GetAdapterDriverVersion2(adapterDriverVersionString
)))
624 if (NS_FAILED(GetAdapterVendorID(adapterVendorID
)) ||
625 NS_FAILED(GetAdapterDeviceID(adapterDeviceID
)) ||
626 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString
)))
632 #if defined(XP_WIN) || defined(ANDROID)
633 uint64_t driverVersion
;
634 ParseDriverVersion(adapterDriverVersionString
, &driverVersion
);
638 if (info
[i
].mOperatingSystem
!= DRIVER_OS_ALL
&&
639 info
[i
].mOperatingSystem
!= os
)
644 if (info
[i
].mOperatingSystemVersion
&& info
[i
].mOperatingSystemVersion
!= OperatingSystemVersion()) {
648 if (!info
[i
].mAdapterVendor
.Equals(GfxDriverInfo::GetDeviceVendor(VendorAll
), nsCaseInsensitiveStringComparator()) &&
649 !info
[i
].mAdapterVendor
.Equals(adapterVendorID
, nsCaseInsensitiveStringComparator())) {
653 if (info
[i
].mDevices
!= GfxDriverInfo::allDevices
&& info
[i
].mDevices
->Length()) {
654 bool deviceMatches
= false;
655 for (uint32_t j
= 0; j
< info
[i
].mDevices
->Length(); j
++) {
656 if ((*info
[i
].mDevices
)[j
].Equals(adapterDeviceID
, nsCaseInsensitiveStringComparator())) {
657 deviceMatches
= true;
662 if (!deviceMatches
) {
669 if (!info
[i
].mHardware
.IsEmpty() && !info
[i
].mHardware
.Equals(Hardware())) {
672 if (!info
[i
].mModel
.IsEmpty() && !info
[i
].mModel
.Equals(Model())) {
675 if (!info
[i
].mProduct
.IsEmpty() && !info
[i
].mProduct
.Equals(Product())) {
678 if (!info
[i
].mManufacturer
.IsEmpty() && !info
[i
].mManufacturer
.Equals(Manufacturer())) {
682 #if defined(XP_WIN) || defined(ANDROID)
683 switch (info
[i
].mComparisonOp
) {
684 case DRIVER_LESS_THAN
:
685 match
= driverVersion
< info
[i
].mDriverVersion
;
687 case DRIVER_LESS_THAN_OR_EQUAL
:
688 match
= driverVersion
<= info
[i
].mDriverVersion
;
690 case DRIVER_GREATER_THAN
:
691 match
= driverVersion
> info
[i
].mDriverVersion
;
693 case DRIVER_GREATER_THAN_OR_EQUAL
:
694 match
= driverVersion
>= info
[i
].mDriverVersion
;
697 match
= driverVersion
== info
[i
].mDriverVersion
;
699 case DRIVER_NOT_EQUAL
:
700 match
= driverVersion
!= info
[i
].mDriverVersion
;
702 case DRIVER_BETWEEN_EXCLUSIVE
:
703 match
= driverVersion
> info
[i
].mDriverVersion
&& driverVersion
< info
[i
].mDriverVersionMax
;
705 case DRIVER_BETWEEN_INCLUSIVE
:
706 match
= driverVersion
>= info
[i
].mDriverVersion
&& driverVersion
<= info
[i
].mDriverVersionMax
;
708 case DRIVER_BETWEEN_INCLUSIVE_START
:
709 match
= driverVersion
>= info
[i
].mDriverVersion
&& driverVersion
< info
[i
].mDriverVersionMax
;
711 case DRIVER_COMPARISON_IGNORED
:
712 // We don't have a comparison op, so we match everything.
716 NS_WARNING("Bogus op in GfxDriverInfo");
720 // We don't care what driver version it was. We only check OS version and if
721 // the device matches.
725 if (match
|| info
[i
].mDriverVersion
== GfxDriverInfo::allDriverVersions
) {
726 if (info
[i
].mFeature
== GfxDriverInfo::allFeatures
||
727 info
[i
].mFeature
== aFeature
)
729 status
= info
[i
].mFeatureStatus
;
736 // As a very special case, we block D2D on machines with an NVidia 310M GPU
737 // as either the primary or secondary adapter. D2D is also blocked when the
738 // NV 310M is the primary adapter (using the standard blocklisting mechanism).
739 // If the primary GPU already matched something in the blocklist then we
740 // ignore this special rule. See bug 1008759.
741 if (status
== nsIGfxInfo::FEATURE_STATUS_UNKNOWN
&&
742 (aFeature
== nsIGfxInfo::FEATURE_DIRECT2D
)) {
743 nsAutoString adapterVendorID2
;
744 nsAutoString adapterDeviceID2
;
745 if ((!NS_FAILED(GetAdapterVendorID2(adapterVendorID2
))) &&
746 (!NS_FAILED(GetAdapterDeviceID2(adapterDeviceID2
))))
748 nsAString
&nvVendorID
= (nsAString
&)GfxDriverInfo::GetDeviceVendor(VendorNVIDIA
);
749 const nsString nv310mDeviceId
= NS_LITERAL_STRING("0x0A70");
750 if (nvVendorID
.Equals(adapterVendorID2
, nsCaseInsensitiveStringComparator()) &&
751 nv310mDeviceId
.Equals(adapterDeviceID2
, nsCaseInsensitiveStringComparator())) {
752 status
= nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
757 // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object
758 // back to the Windows handler, so we must handle this here.
759 if (status
== FEATURE_BLOCKED_DRIVER_VERSION
) {
760 if (info
[i
].mSuggestedVersion
) {
761 aSuggestedVersion
.AppendPrintf("%s", info
[i
].mSuggestedVersion
);
762 } else if (info
[i
].mComparisonOp
== DRIVER_LESS_THAN
&&
763 info
[i
].mDriverVersion
!= GfxDriverInfo::allDriverVersions
)
765 aSuggestedVersion
.AppendPrintf("%lld.%lld.%lld.%lld",
766 (info
[i
].mDriverVersion
& 0xffff000000000000) >> 48,
767 (info
[i
].mDriverVersion
& 0x0000ffff00000000) >> 32,
768 (info
[i
].mDriverVersion
& 0x00000000ffff0000) >> 16,
769 (info
[i
].mDriverVersion
& 0x000000000000ffff));
778 GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature
,
780 nsAString
& aSuggestedVersion
,
781 const nsTArray
<GfxDriverInfo
>& aDriverInfo
,
782 OperatingSystem
* aOS
/* = nullptr */)
784 if (*aStatus
!= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
) {
785 // Terminate now with the status determined by the derived type (OS-specific
790 // If an operating system was provided by the derived GetFeatureStatusImpl,
791 // grab it here. Otherwise, the OS is unknown.
792 OperatingSystem os
= DRIVER_OS_UNKNOWN
;
796 nsAutoString adapterVendorID
;
797 nsAutoString adapterDeviceID
;
798 nsAutoString adapterDriverVersionString
;
799 if (NS_FAILED(GetAdapterVendorID(adapterVendorID
)) ||
800 NS_FAILED(GetAdapterDeviceID(adapterDeviceID
)) ||
801 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString
)))
806 // Check if the device is blocked from the downloaded blocklist. If not, check
807 // the static list after that. This order is used so that we can later escape
808 // out of static blocks (i.e. if we were wrong or something was patched, we
809 // can back out our static block without doing a release).
811 if (aDriverInfo
.Length()) {
812 status
= FindBlocklistedDeviceInList(aDriverInfo
, aSuggestedVersion
, aFeature
, os
);
815 mDriverInfo
= new nsTArray
<GfxDriverInfo
>();
817 status
= FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion
, aFeature
, os
);
820 // It's now done being processed. It's safe to set the status to STATUS_OK.
821 if (status
== nsIGfxInfo::FEATURE_STATUS_UNKNOWN
) {
822 *aStatus
= nsIGfxInfo::FEATURE_STATUS_OK
;
831 GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature
,
835 if (GetPrefValueForDriverVersion(version
)) {
836 aVersion
= NS_ConvertASCIItoUTF16(version
);
841 nsTArray
<GfxDriverInfo
> driverInfo
;
842 return GetFeatureStatusImpl(aFeature
, &status
, aVersion
, driverInfo
);
847 GfxInfoBase::GetWebGLParameter(const nsAString
& aParam
,
850 return GfxInfoWebGL::GetWebGLParameter(aParam
, aResult
);
854 GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray
<GfxDriverInfo
>& aDriverInfo
)
856 int32_t features
[] = {
857 nsIGfxInfo::FEATURE_DIRECT2D
,
858 nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
,
859 nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
,
860 nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
,
861 nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
,
862 nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
,
863 nsIGfxInfo::FEATURE_DXVA
,
864 nsIGfxInfo::FEATURE_OPENGL_LAYERS
,
865 nsIGfxInfo::FEATURE_WEBGL_OPENGL
,
866 nsIGfxInfo::FEATURE_WEBGL_ANGLE
,
867 nsIGfxInfo::FEATURE_WEBGL_MSAA
,
868 nsIGfxInfo::FEATURE_STAGEFRIGHT
,
872 // For every feature we know about, we evaluate whether this blacklist has a
873 // non-STATUS_OK status. If it does, we set the pref we evaluate in
874 // GetFeatureStatus above, so we don't need to hold on to this blacklist
875 // anywhere permanent.
877 while (features
[i
]) {
879 nsAutoString suggestedVersion
;
880 if (NS_SUCCEEDED(GetFeatureStatusImpl(features
[i
], &status
,
885 case nsIGfxInfo::FEATURE_STATUS_OK
:
886 RemovePrefForFeature(features
[i
]);
889 case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
:
890 if (!suggestedVersion
.IsEmpty()) {
891 SetPrefValueForDriverVersion(suggestedVersion
);
893 RemovePrefForDriverVersion();
897 case nsIGfxInfo::FEATURE_BLOCKED_DEVICE
:
898 case nsIGfxInfo::FEATURE_DISCOURAGED
:
899 case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION
:
900 SetPrefValueForFeature(features
[i
], status
);
910 GfxInfoBase::LogFailure(const nsACString
&failure
)
912 // gfxCriticalError has a mutex lock of its own, so we may not actually
913 // need this lock. ::GetFailures() accesses the data but the LogForwarder
914 // will not return the copy of the logs unless it can get the same lock
915 // that gfxCriticalError uses. Still, that is so much of an implementation
916 // detail that it's nicer to just add an extra lock here and in ::GetFailures()
917 MutexAutoLock
lock(mMutex
);
919 // By default, gfxCriticalError asserts; make it not assert in this case.
920 gfxCriticalError(CriticalLog::DefaultOptions(false)) << "(LF) " << failure
.BeginReading();
923 /* void getFailures (out unsigned long failureCount, [optional, array, size_is (failureCount)] out long indices, [array, size_is (failureCount), retval] out string failures); */
924 /* XPConnect method of returning arrays is very ugly. Would not recommend. Fallable nsMemory::Alloc makes things worse */
925 NS_IMETHODIMP
GfxInfoBase::GetFailures(uint32_t* failureCount
,
929 MutexAutoLock
lock(mMutex
);
931 NS_ENSURE_ARG_POINTER(failureCount
);
932 NS_ENSURE_ARG_POINTER(failures
);
937 // indices is "allowed" to be null, the caller may not care about them,
938 // although calling from JS doesn't seem to get us there.
939 if (indices
) *indices
= nullptr;
941 LogForwarder
* logForwarder
= Factory::GetLogForwarder();
943 return NS_ERROR_UNEXPECTED
;
946 // There are two stirng copies in this method, starting with this one. We are
947 // assuming this is not a big deal, as the size of the array should be small
948 // and the strings in it should be small as well (the error messages in the
949 // code.) The second copy happens with the Clone() calls. Technically,
950 // we don't need the mutex lock after the StringVectorCopy() call.
951 std::vector
<std::pair
<int32_t,std::string
> > loggedStrings
= logForwarder
->StringsVectorCopy();
952 *failureCount
= loggedStrings
.size();
954 if (*failureCount
!= 0) {
955 *failures
= (char**)nsMemory::Alloc(*failureCount
* sizeof(char*));
957 return NS_ERROR_OUT_OF_MEMORY
;
960 *indices
= (int32_t*)nsMemory::Alloc(*failureCount
* sizeof(int32_t));
962 nsMemory::Free(*failures
);
964 return NS_ERROR_OUT_OF_MEMORY
;
968 /* copy over the failure messages into the array we just allocated */
969 std::vector
<std::pair
<int32_t, std::string
> >::const_iterator it
;
971 for(it
= loggedStrings
.begin() ; it
!= loggedStrings
.end(); ++it
, i
++) {
972 (*failures
)[i
] = (char*)nsMemory::Clone((*it
).second
.c_str(), (*it
).second
.size() + 1);
973 if (indices
) (*indices
)[i
] = (*it
).first
;
975 if (!(*failures
)[i
]) {
976 /* <sarcasm> I'm too afraid to use an inline function... </sarcasm> */
977 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i
, (*failures
));
979 return NS_ERROR_OUT_OF_MEMORY
;
987 nsTArray
<GfxInfoCollectorBase
*> *sCollectors
;
993 sCollectors
= new nsTArray
<GfxInfoCollectorBase
*>;
996 nsresult
GfxInfoBase::GetInfo(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aResult
)
1001 for (uint32_t i
= 0; i
< sCollectors
->Length(); i
++) {
1002 (*sCollectors
)[i
]->GetInfo(obj
);
1005 // Some example property definitions
1006 // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
1007 // obj.DefineProperty("renderer", mRendererIDsString);
1008 // obj.DefineProperty("five", 5);
1011 return NS_ERROR_FAILURE
;
1014 aResult
.setObject(*obj
.mObj
);
1019 GfxInfoBase::AddCollector(GfxInfoCollectorBase
* collector
)
1022 sCollectors
->AppendElement(collector
);
1026 GfxInfoBase::RemoveCollector(GfxInfoCollectorBase
* collector
)
1029 for (uint32_t i
= 0; i
< sCollectors
->Length(); i
++) {
1030 if ((*sCollectors
)[i
] == collector
) {
1031 sCollectors
->RemoveElementAt(i
);
1035 if (sCollectors
->IsEmpty()) {
1037 sCollectors
= nullptr;
1041 GfxInfoCollectorBase::GfxInfoCollectorBase()
1043 GfxInfoBase::AddCollector(this);
1046 GfxInfoCollectorBase::~GfxInfoCollectorBase()
1048 GfxInfoBase::RemoveCollector(this);