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 <mutex> // std::call_once
14 #include "GfxDriverInfo.h"
15 #include "js/Array.h" // JS::GetArrayLength, JS::NewArrayObject
16 #include "js/PropertyAndElement.h" // JS_SetElement, JS_SetProperty
18 #include "nsCOMArray.h"
20 #include "nsUnicharUtils.h"
21 #include "nsVersionComparator.h"
22 #include "mozilla/Services.h"
23 #include "mozilla/Observer.h"
24 #include "nsIObserver.h"
25 #include "nsIObserverService.h"
27 #include "nsXULAppAPI.h"
28 #include "nsIXULAppInfo.h"
29 #include "mozilla/BinarySearch.h"
30 #include "mozilla/ClearOnShutdown.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/StaticPrefs_gfx.h"
33 #include "mozilla/gfx/2D.h"
34 #include "mozilla/gfx/BuildConstants.h"
35 #include "mozilla/gfx/GPUProcessManager.h"
36 #include "mozilla/gfx/Logging.h"
37 #include "mozilla/gfx/gfxVars.h"
38 #include "mozilla/widget/ScreenManager.h"
39 #include "mozilla/widget/Screen.h"
43 #include "gfxPlatform.h"
44 #include "gfxConfig.h"
45 #include "DriverCrashGuard.h"
47 #ifdef MOZ_WIDGET_ANDROID
49 # include "AndroidBuild.h"
52 using namespace mozilla::widget
;
53 using namespace mozilla
;
54 using mozilla::MutexAutoLock
;
56 nsTArray
<GfxDriverInfo
>* GfxInfoBase::sDriverInfo
;
57 StaticAutoPtr
<nsTArray
<gfx::GfxInfoFeatureStatus
>> GfxInfoBase::sFeatureStatus
;
58 bool GfxInfoBase::sDriverInfoObserverInitialized
;
59 bool GfxInfoBase::sShutdownOccurred
;
61 // Call this when setting sFeatureStatus to a non-null pointer to
62 // ensure destruction even if the GfxInfo component is never instantiated.
63 static void InitFeatureStatus(nsTArray
<gfx::GfxInfoFeatureStatus
>* aPtr
) {
64 static std::once_flag sOnce
;
65 std::call_once(sOnce
, [] { ClearOnShutdown(&GfxInfoBase::sFeatureStatus
); });
66 GfxInfoBase::sFeatureStatus
= aPtr
;
69 // Observes for shutdown so that the child GfxDriverInfo list is freed.
70 class ShutdownObserver
: public nsIObserver
{
71 virtual ~ShutdownObserver() = default;
74 ShutdownObserver() = default;
78 NS_IMETHOD
Observe(nsISupports
* subject
, const char* aTopic
,
79 const char16_t
* aData
) override
{
80 MOZ_ASSERT(strcmp(aTopic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
) == 0);
82 delete GfxInfoBase::sDriverInfo
;
83 GfxInfoBase::sDriverInfo
= nullptr;
85 for (auto& deviceFamily
: GfxDriverInfo::sDeviceFamilies
) {
87 deviceFamily
= nullptr;
90 for (auto& windowProtocol
: GfxDriverInfo::sWindowProtocol
) {
91 delete windowProtocol
;
92 windowProtocol
= nullptr;
95 for (auto& deviceVendor
: GfxDriverInfo::sDeviceVendors
) {
97 deviceVendor
= nullptr;
100 for (auto& driverVendor
: GfxDriverInfo::sDriverVendors
) {
102 driverVendor
= nullptr;
105 GfxInfoBase::sShutdownOccurred
= true;
111 NS_IMPL_ISUPPORTS(ShutdownObserver
, nsIObserver
)
113 static void InitGfxDriverInfoShutdownObserver() {
114 if (GfxInfoBase::sDriverInfoObserverInitialized
) return;
116 GfxInfoBase::sDriverInfoObserverInitialized
= true;
118 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
119 if (!observerService
) {
120 NS_WARNING("Could not get observer service!");
124 ShutdownObserver
* obs
= new ShutdownObserver();
125 observerService
->AddObserver(obs
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
128 using namespace mozilla::widget
;
129 using namespace mozilla::gfx
;
130 using namespace mozilla
;
132 NS_IMPL_ISUPPORTS(GfxInfoBase
, nsIGfxInfo
, nsIObserver
,
133 nsISupportsWeakReference
)
135 #define BLOCKLIST_PREF_BRANCH "gfx.blacklist."
136 #define SUGGESTED_VERSION_PREF BLOCKLIST_PREF_BRANCH "suggested-driver-version"
138 static const char* GetPrefNameForFeature(int32_t aFeature
) {
139 const char* name
= nullptr;
141 case nsIGfxInfo::FEATURE_DIRECT2D
:
142 name
= BLOCKLIST_PREF_BRANCH
"direct2d";
144 case nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
:
145 name
= BLOCKLIST_PREF_BRANCH
"layers.direct3d9";
147 case nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
:
148 name
= BLOCKLIST_PREF_BRANCH
"layers.direct3d10";
150 case nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
:
151 name
= BLOCKLIST_PREF_BRANCH
"layers.direct3d10-1";
153 case nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
:
154 name
= BLOCKLIST_PREF_BRANCH
"layers.direct3d11";
156 case nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
:
157 name
= BLOCKLIST_PREF_BRANCH
"direct3d11angle";
159 case nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING
:
160 name
= BLOCKLIST_PREF_BRANCH
"hardwarevideodecoding";
162 case nsIGfxInfo::FEATURE_OPENGL_LAYERS
:
163 name
= BLOCKLIST_PREF_BRANCH
"layers.opengl";
165 case nsIGfxInfo::FEATURE_WEBGL_OPENGL
:
166 name
= BLOCKLIST_PREF_BRANCH
"webgl.opengl";
168 case nsIGfxInfo::FEATURE_WEBGL_ANGLE
:
169 name
= BLOCKLIST_PREF_BRANCH
"webgl.angle";
171 case nsIGfxInfo::UNUSED_FEATURE_WEBGL_MSAA
:
172 name
= BLOCKLIST_PREF_BRANCH
"webgl.msaa";
174 case nsIGfxInfo::FEATURE_STAGEFRIGHT
:
175 name
= BLOCKLIST_PREF_BRANCH
"stagefright";
177 case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_H264
:
178 name
= BLOCKLIST_PREF_BRANCH
"webrtc.hw.acceleration.h264";
180 case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE
:
181 name
= BLOCKLIST_PREF_BRANCH
"webrtc.hw.acceleration.encode";
183 case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE
:
184 name
= BLOCKLIST_PREF_BRANCH
"webrtc.hw.acceleration.decode";
186 case nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION
:
187 name
= BLOCKLIST_PREF_BRANCH
"canvas2d.acceleration";
189 case nsIGfxInfo::FEATURE_DX_INTEROP2
:
190 name
= BLOCKLIST_PREF_BRANCH
"dx.interop2";
192 case nsIGfxInfo::FEATURE_GPU_PROCESS
:
193 name
= BLOCKLIST_PREF_BRANCH
"gpu.process";
195 case nsIGfxInfo::FEATURE_WEBGL2
:
196 name
= BLOCKLIST_PREF_BRANCH
"webgl2";
198 case nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX
:
199 name
= BLOCKLIST_PREF_BRANCH
"d3d11.keyed.mutex";
201 case nsIGfxInfo::FEATURE_WEBRENDER
:
202 name
= BLOCKLIST_PREF_BRANCH
"webrender";
204 case nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR
:
205 name
= BLOCKLIST_PREF_BRANCH
"webrender.compositor";
207 case nsIGfxInfo::FEATURE_DX_NV12
:
208 name
= BLOCKLIST_PREF_BRANCH
"dx.nv12";
210 case nsIGfxInfo::FEATURE_DX_P010
:
211 name
= BLOCKLIST_PREF_BRANCH
"dx.p010";
213 case nsIGfxInfo::FEATURE_DX_P016
:
214 name
= BLOCKLIST_PREF_BRANCH
"dx.p016";
216 case nsIGfxInfo::FEATURE_VP8_HW_DECODE
:
217 name
= BLOCKLIST_PREF_BRANCH
"vp8.hw-decode";
219 case nsIGfxInfo::FEATURE_VP9_HW_DECODE
:
220 name
= BLOCKLIST_PREF_BRANCH
"vp9.hw-decode";
222 case nsIGfxInfo::FEATURE_GL_SWIZZLE
:
223 name
= BLOCKLIST_PREF_BRANCH
"gl.swizzle";
225 case nsIGfxInfo::FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS
:
226 name
= BLOCKLIST_PREF_BRANCH
"webrender.scissored_cache_clears";
228 case nsIGfxInfo::FEATURE_ALLOW_WEBGL_OUT_OF_PROCESS
:
229 name
= BLOCKLIST_PREF_BRANCH
"webgl.allow-oop";
231 case nsIGfxInfo::FEATURE_THREADSAFE_GL
:
232 name
= BLOCKLIST_PREF_BRANCH
"gl.threadsafe";
234 case nsIGfxInfo::FEATURE_WEBRENDER_OPTIMIZED_SHADERS
:
235 name
= BLOCKLIST_PREF_BRANCH
"webrender.optimized-shaders";
237 case nsIGfxInfo::FEATURE_X11_EGL
:
238 name
= BLOCKLIST_PREF_BRANCH
"x11.egl";
240 case nsIGfxInfo::FEATURE_DMABUF
:
241 name
= BLOCKLIST_PREF_BRANCH
"dmabuf";
243 case nsIGfxInfo::FEATURE_WEBGPU
:
244 name
= BLOCKLIST_PREF_BRANCH
"webgpu";
246 case nsIGfxInfo::FEATURE_VIDEO_OVERLAY
:
247 name
= BLOCKLIST_PREF_BRANCH
"video-overlay";
249 case nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY
:
250 name
= BLOCKLIST_PREF_BRANCH
"hw-video-zero-copy";
252 case nsIGfxInfo::FEATURE_WEBRENDER_SHADER_CACHE
:
253 name
= BLOCKLIST_PREF_BRANCH
"webrender.program-binary-disk";
255 case nsIGfxInfo::FEATURE_WEBRENDER_PARTIAL_PRESENT
:
256 name
= BLOCKLIST_PREF_BRANCH
"webrender.partial-present";
258 case nsIGfxInfo::FEATURE_DMABUF_SURFACE_EXPORT
:
259 name
= BLOCKLIST_PREF_BRANCH
"dmabuf.surface-export";
261 case nsIGfxInfo::FEATURE_REUSE_DECODER_DEVICE
:
262 name
= BLOCKLIST_PREF_BRANCH
"reuse-decoder-device";
264 case nsIGfxInfo::FEATURE_BACKDROP_FILTER
:
265 name
= BLOCKLIST_PREF_BRANCH
"backdrop.filter";
267 case nsIGfxInfo::FEATURE_ACCELERATED_CANVAS2D
:
268 name
= BLOCKLIST_PREF_BRANCH
"accelerated-canvas2d";
270 case nsIGfxInfo::FEATURE_H264_HW_DECODE
:
271 name
= BLOCKLIST_PREF_BRANCH
"h264.hw-decode";
273 case nsIGfxInfo::FEATURE_AV1_HW_DECODE
:
274 name
= BLOCKLIST_PREF_BRANCH
"av1.hw-decode";
276 case nsIGfxInfo::FEATURE_VIDEO_SOFTWARE_OVERLAY
:
277 name
= BLOCKLIST_PREF_BRANCH
"video-software-overlay";
279 case nsIGfxInfo::FEATURE_WEBGL_USE_HARDWARE
:
280 name
= BLOCKLIST_PREF_BRANCH
"webgl-use-hardware";
282 case nsIGfxInfo::FEATURE_OVERLAY_VP_AUTO_HDR
:
283 name
= BLOCKLIST_PREF_BRANCH
"overlay-vp-auto-hdr";
285 case nsIGfxInfo::FEATURE_OVERLAY_VP_SUPER_RESOLUTION
:
286 name
= BLOCKLIST_PREF_BRANCH
"overlay-vp-super-resolution";
289 MOZ_ASSERT_UNREACHABLE("Unexpected nsIGfxInfo feature?!");
296 // Returns the value of the pref for the relevant feature in aValue.
297 // If the pref doesn't exist, aValue is not touched, and returns false.
298 static bool GetPrefValueForFeature(int32_t aFeature
, int32_t& aValue
,
299 nsACString
& aFailureId
) {
300 const char* prefname
= GetPrefNameForFeature(aFeature
);
301 if (!prefname
) return false;
303 aValue
= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
;
304 if (!NS_SUCCEEDED(Preferences::GetInt(prefname
, &aValue
))) {
308 if (aValue
== nsIGfxInfo::FEATURE_DENIED
) {
309 // We should never see the DENIED status with the downloadable blocklist.
313 nsCString
failureprefname(prefname
);
314 failureprefname
+= ".failureid";
315 nsAutoCString failureValue
;
316 nsresult rv
= Preferences::GetCString(failureprefname
.get(), failureValue
);
317 if (NS_SUCCEEDED(rv
)) {
318 aFailureId
= failureValue
.get();
320 aFailureId
= "FEATURE_FAILURE_BLOCKLIST_PREF";
326 static void SetPrefValueForFeature(int32_t aFeature
, int32_t aValue
,
327 const nsACString
& aFailureId
) {
328 const char* prefname
= GetPrefNameForFeature(aFeature
);
329 if (!prefname
) return;
330 if (XRE_IsParentProcess()) {
331 GfxInfoBase::sFeatureStatus
= nullptr;
334 Preferences::SetInt(prefname
, aValue
);
335 if (!aFailureId
.IsEmpty()) {
336 nsAutoCString
failureprefname(prefname
);
337 failureprefname
+= ".failureid";
338 Preferences::SetCString(failureprefname
.get(), aFailureId
);
342 static void RemovePrefForFeature(int32_t aFeature
) {
343 const char* prefname
= GetPrefNameForFeature(aFeature
);
344 if (!prefname
) return;
346 if (XRE_IsParentProcess()) {
347 GfxInfoBase::sFeatureStatus
= nullptr;
349 Preferences::ClearUser(prefname
);
352 static bool GetPrefValueForDriverVersion(nsCString
& aVersion
) {
354 Preferences::GetCString(SUGGESTED_VERSION_PREF
, aVersion
));
357 static void SetPrefValueForDriverVersion(const nsAString
& aVersion
) {
358 Preferences::SetString(SUGGESTED_VERSION_PREF
, aVersion
);
361 static void RemovePrefForDriverVersion() {
362 Preferences::ClearUser(SUGGESTED_VERSION_PREF
);
365 static OperatingSystem
BlocklistOSToOperatingSystem(const nsAString
& os
) {
366 if (os
.EqualsLiteral("WINNT 6.1")) {
367 return OperatingSystem::Windows7
;
369 if (os
.EqualsLiteral("WINNT 6.2")) {
370 return OperatingSystem::Windows8
;
372 if (os
.EqualsLiteral("WINNT 6.3")) {
373 return OperatingSystem::Windows8_1
;
375 if (os
.EqualsLiteral("WINNT 10.0")) {
376 return OperatingSystem::Windows10
;
378 if (os
.EqualsLiteral("Linux")) {
379 return OperatingSystem::Linux
;
381 if (os
.EqualsLiteral("Darwin 9")) {
382 return OperatingSystem::OSX10_5
;
384 if (os
.EqualsLiteral("Darwin 10")) {
385 return OperatingSystem::OSX10_6
;
387 if (os
.EqualsLiteral("Darwin 11")) {
388 return OperatingSystem::OSX10_7
;
390 if (os
.EqualsLiteral("Darwin 12")) {
391 return OperatingSystem::OSX10_8
;
393 if (os
.EqualsLiteral("Darwin 13")) {
394 return OperatingSystem::OSX10_9
;
396 if (os
.EqualsLiteral("Darwin 14")) {
397 return OperatingSystem::OSX10_10
;
399 if (os
.EqualsLiteral("Darwin 15")) {
400 return OperatingSystem::OSX10_11
;
402 if (os
.EqualsLiteral("Darwin 16")) {
403 return OperatingSystem::OSX10_12
;
405 if (os
.EqualsLiteral("Darwin 17")) {
406 return OperatingSystem::OSX10_13
;
408 if (os
.EqualsLiteral("Darwin 18")) {
409 return OperatingSystem::OSX10_14
;
411 if (os
.EqualsLiteral("Darwin 19")) {
412 return OperatingSystem::OSX10_15
;
414 if (os
.EqualsLiteral("Darwin 20")) {
415 return OperatingSystem::OSX11_0
;
417 if (os
.EqualsLiteral("Android")) {
418 return OperatingSystem::Android
;
419 // For historical reasons, "All" in blocklist means "All Windows"
421 if (os
.EqualsLiteral("All")) {
422 return OperatingSystem::Windows
;
424 if (os
.EqualsLiteral("Darwin")) {
425 return OperatingSystem::OSX
;
428 return OperatingSystem::Unknown
;
431 static GfxDeviceFamily
* BlocklistDevicesToDeviceFamily(
432 nsTArray
<nsCString
>& devices
) {
433 if (devices
.Length() == 0) return nullptr;
435 // For each device, get its device ID, and return a freshly-allocated
436 // GfxDeviceFamily with the contents of that array.
437 GfxDeviceFamily
* deviceIds
= new GfxDeviceFamily
;
439 for (uint32_t i
= 0; i
< devices
.Length(); ++i
) {
440 // We make sure we don't add any "empty" device entries to the array, so
441 // we don't need to check if devices[i] is empty.
442 deviceIds
->Append(NS_ConvertUTF8toUTF16(devices
[i
]));
448 static int32_t BlocklistFeatureToGfxFeature(const nsAString
& aFeature
) {
449 MOZ_ASSERT(!aFeature
.IsEmpty());
450 if (aFeature
.EqualsLiteral("DIRECT2D")) {
451 return nsIGfxInfo::FEATURE_DIRECT2D
;
453 if (aFeature
.EqualsLiteral("DIRECT3D_9_LAYERS")) {
454 return nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS
;
456 if (aFeature
.EqualsLiteral("DIRECT3D_10_LAYERS")) {
457 return nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS
;
459 if (aFeature
.EqualsLiteral("DIRECT3D_10_1_LAYERS")) {
460 return nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS
;
462 if (aFeature
.EqualsLiteral("DIRECT3D_11_LAYERS")) {
463 return nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS
;
465 if (aFeature
.EqualsLiteral("DIRECT3D_11_ANGLE")) {
466 return nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
;
468 if (aFeature
.EqualsLiteral("HARDWARE_VIDEO_DECODING")) {
469 return nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING
;
471 if (aFeature
.EqualsLiteral("OPENGL_LAYERS")) {
472 return nsIGfxInfo::FEATURE_OPENGL_LAYERS
;
474 if (aFeature
.EqualsLiteral("WEBGL_OPENGL")) {
475 return nsIGfxInfo::FEATURE_WEBGL_OPENGL
;
477 if (aFeature
.EqualsLiteral("WEBGL_ANGLE")) {
478 return nsIGfxInfo::FEATURE_WEBGL_ANGLE
;
480 if (aFeature
.EqualsLiteral("WEBGL_MSAA")) {
481 return nsIGfxInfo::UNUSED_FEATURE_WEBGL_MSAA
;
483 if (aFeature
.EqualsLiteral("STAGEFRIGHT")) {
484 return nsIGfxInfo::FEATURE_STAGEFRIGHT
;
486 if (aFeature
.EqualsLiteral("WEBRTC_HW_ACCELERATION_ENCODE")) {
487 return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE
;
489 if (aFeature
.EqualsLiteral("WEBRTC_HW_ACCELERATION_DECODE")) {
490 return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE
;
492 if (aFeature
.EqualsLiteral("WEBRTC_HW_ACCELERATION_H264")) {
493 return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_H264
;
495 if (aFeature
.EqualsLiteral("CANVAS2D_ACCELERATION")) {
496 return nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION
;
498 if (aFeature
.EqualsLiteral("DX_INTEROP2")) {
499 return nsIGfxInfo::FEATURE_DX_INTEROP2
;
501 if (aFeature
.EqualsLiteral("GPU_PROCESS")) {
502 return nsIGfxInfo::FEATURE_GPU_PROCESS
;
504 if (aFeature
.EqualsLiteral("WEBGL2")) {
505 return nsIGfxInfo::FEATURE_WEBGL2
;
507 if (aFeature
.EqualsLiteral("D3D11_KEYED_MUTEX")) {
508 return nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX
;
510 if (aFeature
.EqualsLiteral("WEBRENDER")) {
511 return nsIGfxInfo::FEATURE_WEBRENDER
;
513 if (aFeature
.EqualsLiteral("WEBRENDER_COMPOSITOR")) {
514 return nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR
;
516 if (aFeature
.EqualsLiteral("DX_NV12")) {
517 return nsIGfxInfo::FEATURE_DX_NV12
;
519 if (aFeature
.EqualsLiteral("VP8_HW_DECODE")) {
520 return nsIGfxInfo::FEATURE_VP8_HW_DECODE
;
522 if (aFeature
.EqualsLiteral("VP9_HW_DECODE")) {
523 return nsIGfxInfo::FEATURE_VP9_HW_DECODE
;
525 if (aFeature
.EqualsLiteral("GL_SWIZZLE")) {
526 return nsIGfxInfo::FEATURE_GL_SWIZZLE
;
528 if (aFeature
.EqualsLiteral("WEBRENDER_SCISSORED_CACHE_CLEARS")) {
529 return nsIGfxInfo::FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS
;
531 if (aFeature
.EqualsLiteral("ALLOW_WEBGL_OUT_OF_PROCESS")) {
532 return nsIGfxInfo::FEATURE_ALLOW_WEBGL_OUT_OF_PROCESS
;
534 if (aFeature
.EqualsLiteral("THREADSAFE_GL")) {
535 return nsIGfxInfo::FEATURE_THREADSAFE_GL
;
537 if (aFeature
.EqualsLiteral("X11_EGL")) {
538 return nsIGfxInfo::FEATURE_X11_EGL
;
540 if (aFeature
.EqualsLiteral("DMABUF")) {
541 return nsIGfxInfo::FEATURE_DMABUF
;
543 if (aFeature
.EqualsLiteral("WEBGPU")) {
544 return nsIGfxInfo::FEATURE_WEBGPU
;
546 if (aFeature
.EqualsLiteral("VIDEO_OVERLAY")) {
547 return nsIGfxInfo::FEATURE_VIDEO_OVERLAY
;
549 if (aFeature
.EqualsLiteral("HW_DECODED_VIDEO_ZERO_COPY")) {
550 return nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY
;
552 if (aFeature
.EqualsLiteral("REUSE_DECODER_DEVICE")) {
553 return nsIGfxInfo::FEATURE_REUSE_DECODER_DEVICE
;
555 if (aFeature
.EqualsLiteral("WEBRENDER_PARTIAL_PRESENT")) {
556 return nsIGfxInfo::FEATURE_WEBRENDER_PARTIAL_PRESENT
;
558 if (aFeature
.EqualsLiteral("BACKDROP_FILTER")) {
559 return nsIGfxInfo::FEATURE_BACKDROP_FILTER
;
561 if (aFeature
.EqualsLiteral("ACCELERATED_CANVAS2D")) {
562 return nsIGfxInfo::FEATURE_ACCELERATED_CANVAS2D
;
564 if (aFeature
.EqualsLiteral("FEATURE_OVERLAY_VP_AUTO_HDR")) {
565 return nsIGfxInfo::FEATURE_OVERLAY_VP_AUTO_HDR
;
567 if (aFeature
.EqualsLiteral("FEATURE_OVERLAY_VP_SUPER_RESOLUTION")) {
568 return nsIGfxInfo::FEATURE_OVERLAY_VP_SUPER_RESOLUTION
;
570 if (aFeature
.EqualsLiteral("ALL")) {
571 return GfxDriverInfo::allFeatures
;
573 if (aFeature
.EqualsLiteral("OPTIONAL")) {
574 return GfxDriverInfo::optionalFeatures
;
577 // If we don't recognize the feature, it may be new, and something
578 // this version doesn't understand. So, nothing to do. This is
579 // different from feature not being specified at all, in which case
580 // this method should not get called and we should continue with the
581 // "optional features" blocklisting.
585 static int32_t BlocklistFeatureStatusToGfxFeatureStatus(
586 const nsAString
& aStatus
) {
587 if (aStatus
.EqualsLiteral("STATUS_OK")) {
588 return nsIGfxInfo::FEATURE_STATUS_OK
;
590 if (aStatus
.EqualsLiteral("BLOCKED_DRIVER_VERSION")) {
591 return nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
;
593 if (aStatus
.EqualsLiteral("BLOCKED_DEVICE")) {
594 return nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
596 if (aStatus
.EqualsLiteral("DISCOURAGED")) {
597 return nsIGfxInfo::FEATURE_DISCOURAGED
;
599 if (aStatus
.EqualsLiteral("BLOCKED_OS_VERSION")) {
600 return nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION
;
602 if (aStatus
.EqualsLiteral("DENIED")) {
603 return nsIGfxInfo::FEATURE_DENIED
;
605 if (aStatus
.EqualsLiteral("ALLOW_QUALIFIED")) {
606 return nsIGfxInfo::FEATURE_ALLOW_QUALIFIED
;
608 if (aStatus
.EqualsLiteral("ALLOW_ALWAYS")) {
609 return nsIGfxInfo::FEATURE_ALLOW_ALWAYS
;
612 // Do not allow it to set STATUS_UNKNOWN. Also, we are not
613 // expecting the "mismatch" status showing up here.
615 return nsIGfxInfo::FEATURE_STATUS_OK
;
618 static VersionComparisonOp
BlocklistComparatorToComparisonOp(
619 const nsAString
& op
) {
620 if (op
.EqualsLiteral("LESS_THAN")) {
621 return DRIVER_LESS_THAN
;
623 if (op
.EqualsLiteral("BUILD_ID_LESS_THAN")) {
624 return DRIVER_BUILD_ID_LESS_THAN
;
626 if (op
.EqualsLiteral("LESS_THAN_OR_EQUAL")) {
627 return DRIVER_LESS_THAN_OR_EQUAL
;
629 if (op
.EqualsLiteral("BUILD_ID_LESS_THAN_OR_EQUAL")) {
630 return DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL
;
632 if (op
.EqualsLiteral("GREATER_THAN")) {
633 return DRIVER_GREATER_THAN
;
635 if (op
.EqualsLiteral("GREATER_THAN_OR_EQUAL")) {
636 return DRIVER_GREATER_THAN_OR_EQUAL
;
638 if (op
.EqualsLiteral("EQUAL")) {
641 if (op
.EqualsLiteral("NOT_EQUAL")) {
642 return DRIVER_NOT_EQUAL
;
644 if (op
.EqualsLiteral("BETWEEN_EXCLUSIVE")) {
645 return DRIVER_BETWEEN_EXCLUSIVE
;
647 if (op
.EqualsLiteral("BETWEEN_INCLUSIVE")) {
648 return DRIVER_BETWEEN_INCLUSIVE
;
650 if (op
.EqualsLiteral("BETWEEN_INCLUSIVE_START")) {
651 return DRIVER_BETWEEN_INCLUSIVE_START
;
654 return DRIVER_COMPARISON_IGNORED
;
658 Deserialize Blocklist entries from string.
660 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
662 static bool BlocklistEntryToDriverInfo(const nsACString
& aBlocklistEntry
,
663 GfxDriverInfo
& aDriverInfo
) {
664 // If we get an application version to be zero, something is not working
665 // and we are not going to bother checking the blocklist versions.
666 // See TestGfxWidgets.cpp for how version comparison works.
667 // <versionRange minVersion="42.0a1" maxVersion="45.0"></versionRange>
668 static mozilla::Version
zeroV("0");
669 static mozilla::Version
appV(GfxInfoBase::GetApplicationVersion().get());
671 gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false))
672 << "Invalid application version "
673 << GfxInfoBase::GetApplicationVersion().get();
676 aDriverInfo
.mRuleId
= "FEATURE_FAILURE_DL_BLOCKLIST_NO_ID"_ns
;
678 for (const auto& keyValue
: aBlocklistEntry
.Split('\t')) {
679 nsTArray
<nsCString
> splitted
;
680 ParseString(keyValue
, ':', splitted
);
681 if (splitted
.Length() != 2) {
682 // If we don't recognize the input data, we do not want to proceed.
683 gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false))
684 << "Unrecognized data " << nsCString(keyValue
).get();
687 const nsCString
& key
= splitted
[0];
688 const nsCString
& value
= splitted
[1];
689 NS_ConvertUTF8toUTF16
dataValue(value
);
691 if (value
.Length() == 0) {
692 // Safety check for empty values.
693 gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false))
694 << "Empty value for " << key
.get();
698 if (key
.EqualsLiteral("blockID")) {
699 nsCString blockIdStr
= "FEATURE_FAILURE_DL_BLOCKLIST_"_ns
+ value
;
700 aDriverInfo
.mRuleId
= blockIdStr
.get();
701 } else if (key
.EqualsLiteral("os")) {
702 aDriverInfo
.mOperatingSystem
= BlocklistOSToOperatingSystem(dataValue
);
703 } else if (key
.EqualsLiteral("osversion")) {
704 aDriverInfo
.mOperatingSystemVersion
= strtoul(value
.get(), nullptr, 10);
705 } else if (key
.EqualsLiteral("windowProtocol")) {
706 aDriverInfo
.mWindowProtocol
= dataValue
;
707 } else if (key
.EqualsLiteral("vendor")) {
708 aDriverInfo
.mAdapterVendor
= dataValue
;
709 } else if (key
.EqualsLiteral("driverVendor")) {
710 aDriverInfo
.mDriverVendor
= dataValue
;
711 } else if (key
.EqualsLiteral("feature")) {
712 aDriverInfo
.mFeature
= BlocklistFeatureToGfxFeature(dataValue
);
713 if (aDriverInfo
.mFeature
== 0) {
714 // If we don't recognize the feature, we do not want to proceed.
715 gfxWarning() << "Unrecognized feature " << value
.get();
718 } else if (key
.EqualsLiteral("featureStatus")) {
719 aDriverInfo
.mFeatureStatus
=
720 BlocklistFeatureStatusToGfxFeatureStatus(dataValue
);
721 } else if (key
.EqualsLiteral("driverVersion")) {
723 if (ParseDriverVersion(dataValue
, &version
))
724 aDriverInfo
.mDriverVersion
= version
;
725 } else if (key
.EqualsLiteral("driverVersionMax")) {
727 if (ParseDriverVersion(dataValue
, &version
))
728 aDriverInfo
.mDriverVersionMax
= version
;
729 } else if (key
.EqualsLiteral("driverVersionComparator")) {
730 aDriverInfo
.mComparisonOp
= BlocklistComparatorToComparisonOp(dataValue
);
731 } else if (key
.EqualsLiteral("model")) {
732 aDriverInfo
.mModel
= dataValue
;
733 } else if (key
.EqualsLiteral("product")) {
734 aDriverInfo
.mProduct
= dataValue
;
735 } else if (key
.EqualsLiteral("manufacturer")) {
736 aDriverInfo
.mManufacturer
= dataValue
;
737 } else if (key
.EqualsLiteral("hardware")) {
738 aDriverInfo
.mHardware
= dataValue
;
739 } else if (key
.EqualsLiteral("versionRange")) {
740 nsTArray
<nsCString
> versionRange
;
741 ParseString(value
, ',', versionRange
);
742 if (versionRange
.Length() != 2) {
743 gfxCriticalErrorOnce(CriticalLog::DefaultOptions(false))
744 << "Unrecognized versionRange " << value
.get();
747 const nsCString
& minValue
= versionRange
[0];
748 const nsCString
& maxValue
= versionRange
[1];
750 mozilla::Version
minV(minValue
.get());
751 mozilla::Version
maxV(maxValue
.get());
753 if (minV
> zeroV
&& !(appV
>= minV
)) {
754 // The version of the application is less than the minimal version
755 // this blocklist entry applies to, so we can just ignore it by
756 // returning false and letting the caller deal with it.
759 if (maxV
> zeroV
&& !(appV
<= maxV
)) {
760 // The version of the application is more than the maximal version
761 // this blocklist entry applies to, so we can just ignore it by
762 // returning false and letting the caller deal with it.
765 } else if (key
.EqualsLiteral("devices")) {
766 nsTArray
<nsCString
> devices
;
767 ParseString(value
, ',', devices
);
768 GfxDeviceFamily
* deviceIds
= BlocklistDevicesToDeviceFamily(devices
);
770 // Get GfxDriverInfo to adopt the devices array we created.
771 aDriverInfo
.mDeleteDevices
= true;
772 aDriverInfo
.mDevices
= deviceIds
;
775 // We explicitly ignore unknown elements.
782 GfxInfoBase::Observe(nsISupports
* aSubject
, const char* aTopic
,
783 const char16_t
* aData
) {
784 if (strcmp(aTopic
, "blocklist-data-gfxItems") == 0) {
785 nsTArray
<GfxDriverInfo
> driverInfo
;
786 NS_ConvertUTF16toUTF8
utf8Data(aData
);
788 for (const auto& blocklistEntry
: utf8Data
.Split('\n')) {
790 if (BlocklistEntryToDriverInfo(blocklistEntry
, di
)) {
791 // XXX Changing this to driverInfo.AppendElement(di) causes leaks.
792 // Probably some non-standard semantics of the copy/move operations?
793 *driverInfo
.AppendElement() = di
;
794 // Prevent di falling out of scope from destroying the devices.
795 di
.mDeleteDevices
= false;
797 driverInfo
.AppendElement();
801 EvaluateDownloadedBlocklist(driverInfo
);
807 GfxInfoBase::GfxInfoBase() : mScreenPixels(INT64_MAX
), mMutex("GfxInfoBase") {}
809 GfxInfoBase::~GfxInfoBase() = default;
811 nsresult
GfxInfoBase::Init() {
812 InitGfxDriverInfoShutdownObserver();
814 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
816 os
->AddObserver(this, "blocklist-data-gfxItems", true);
822 void GfxInfoBase::GetData() {
823 if (mScreenPixels
!= INT64_MAX
) {
824 // Already initialized.
828 ScreenManager::GetSingleton().GetTotalScreenPixels(&mScreenPixels
);
832 GfxInfoBase::GetFeatureStatus(int32_t aFeature
, nsACString
& aFailureId
,
834 // Ignore the gfx.blocklist.all pref on release and beta.
835 #if defined(RELEASE_OR_BETA)
836 int32_t blocklistAll
= 0;
838 int32_t blocklistAll
= StaticPrefs::gfx_blocklist_all_AtStartup();
840 if (blocklistAll
> 0) {
841 gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false))
842 << "Forcing blocklisting all features";
843 *aStatus
= FEATURE_BLOCKED_DEVICE
;
844 aFailureId
= "FEATURE_FAILURE_BLOCK_ALL";
848 if (blocklistAll
< 0) {
849 gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false))
850 << "Ignoring any feature blocklisting.";
851 *aStatus
= FEATURE_STATUS_OK
;
855 // This is how we evaluate the downloadable blocklist. If there is no pref,
856 // then we will fallback to checking the static blocklist.
857 if (GetPrefValueForFeature(aFeature
, *aStatus
, aFailureId
)) {
861 if (XRE_IsContentProcess() || XRE_IsGPUProcess()) {
862 // Use the cached data received from the parent process.
863 MOZ_ASSERT(sFeatureStatus
);
864 bool success
= false;
865 for (const auto& fs
: *sFeatureStatus
) {
866 if (fs
.feature() == aFeature
) {
867 aFailureId
= fs
.failureId();
868 *aStatus
= fs
.status();
873 return success
? NS_OK
: NS_ERROR_FAILURE
;
877 nsTArray
<GfxDriverInfo
> driverInfo
;
879 GetFeatureStatusImpl(aFeature
, aStatus
, version
, driverInfo
, aFailureId
);
883 nsTArray
<gfx::GfxInfoFeatureStatus
> GfxInfoBase::GetAllFeatures() {
884 MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
885 if (!sFeatureStatus
) {
886 InitFeatureStatus(new nsTArray
<gfx::GfxInfoFeatureStatus
>());
887 for (int32_t i
= 1; i
<= nsIGfxInfo::FEATURE_MAX_VALUE
; ++i
) {
889 nsAutoCString failureId
;
890 GetFeatureStatus(i
, failureId
, &status
);
891 gfx::GfxInfoFeatureStatus gfxFeatureStatus
;
892 gfxFeatureStatus
.feature() = i
;
893 gfxFeatureStatus
.status() = status
;
894 gfxFeatureStatus
.failureId() = failureId
;
895 sFeatureStatus
->AppendElement(gfxFeatureStatus
);
899 nsTArray
<gfx::GfxInfoFeatureStatus
> features
;
900 for (const auto& status
: *sFeatureStatus
) {
901 gfx::GfxInfoFeatureStatus copy
= status
;
902 features
.AppendElement(copy
);
907 inline bool MatchingAllowStatus(int32_t aStatus
) {
909 case nsIGfxInfo::FEATURE_ALLOW_ALWAYS
:
910 case nsIGfxInfo::FEATURE_ALLOW_QUALIFIED
:
917 // Matching OS go somewhat beyond the simple equality check because of the
918 // "All Windows" and "All OS X" variations.
920 // aBlockedOS is describing the system(s) we are trying to block.
921 // aSystemOS is describing the system we are running on.
923 // aSystemOS should not be "Windows" or "OSX" - it should be set to
924 // a particular version instead.
925 // However, it is valid for aBlockedOS to be one of those generic values,
926 // as we could be blocking all of the versions.
927 inline bool MatchingOperatingSystems(OperatingSystem aBlockedOS
,
928 OperatingSystem aSystemOS
,
929 uint32_t aSystemOSBuild
) {
930 MOZ_ASSERT(aSystemOS
!= OperatingSystem::Windows
&&
931 aSystemOS
!= OperatingSystem::OSX
);
933 // If the block entry OS is unknown, it doesn't match
934 if (aBlockedOS
== OperatingSystem::Unknown
) {
939 if (aBlockedOS
== OperatingSystem::Windows
) {
940 // We do want even "unknown" aSystemOS to fall under "all windows"
944 constexpr uint32_t kMinWin10BuildNumber
= 18362;
945 if (aBlockedOS
== OperatingSystem::RecentWindows10
&&
946 aSystemOS
== OperatingSystem::Windows10
) {
947 // For allowlist purposes, we sometimes want to restrict to only recent
948 // versions of Windows 10. This is a bit of a kludge but easier than adding
949 // complicated blocklist infrastructure for build ID comparisons like driver
951 return aSystemOSBuild
>= kMinWin10BuildNumber
;
954 if (aBlockedOS
== OperatingSystem::NotRecentWindows10
) {
955 if (aSystemOS
== OperatingSystem::Windows10
) {
956 return aSystemOSBuild
< kMinWin10BuildNumber
;
963 #if defined(XP_MACOSX)
964 if (aBlockedOS
== OperatingSystem::OSX
) {
965 // We do want even "unknown" aSystemOS to fall under "all OS X"
970 return aSystemOS
== aBlockedOS
;
973 inline bool MatchingBattery(BatteryStatus aBatteryStatus
, bool aHasBattery
) {
974 switch (aBatteryStatus
) {
975 case BatteryStatus::All
:
977 case BatteryStatus::None
:
979 case BatteryStatus::Present
:
983 MOZ_ASSERT_UNREACHABLE("bad battery status");
987 inline bool MatchingScreenSize(ScreenSizeStatus aScreenStatus
,
988 int64_t aScreenPixels
) {
989 constexpr int64_t kMaxSmallPixels
= 2304000; // 1920x1200
990 constexpr int64_t kMaxMediumPixels
= 4953600; // 3440x1440
992 switch (aScreenStatus
) {
993 case ScreenSizeStatus::All
:
995 case ScreenSizeStatus::Small
:
996 return aScreenPixels
<= kMaxSmallPixels
;
997 case ScreenSizeStatus::SmallAndMedium
:
998 return aScreenPixels
<= kMaxMediumPixels
;
999 case ScreenSizeStatus::Medium
:
1000 return aScreenPixels
> kMaxSmallPixels
&&
1001 aScreenPixels
<= kMaxMediumPixels
;
1002 case ScreenSizeStatus::MediumAndLarge
:
1003 return aScreenPixels
> kMaxSmallPixels
;
1004 case ScreenSizeStatus::Large
:
1005 return aScreenPixels
> kMaxMediumPixels
;
1008 MOZ_ASSERT_UNREACHABLE("bad screen status");
1012 int32_t GfxInfoBase::FindBlocklistedDeviceInList(
1013 const nsTArray
<GfxDriverInfo
>& info
, nsAString
& aSuggestedVersion
,
1014 int32_t aFeature
, nsACString
& aFailureId
, OperatingSystem os
,
1015 bool aForAllowing
) {
1016 int32_t status
= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
;
1018 // Some properties are not available on all platforms.
1019 nsAutoString windowProtocol
;
1020 nsresult rv
= GetWindowProtocol(windowProtocol
);
1021 if (NS_FAILED(rv
) && rv
!= NS_ERROR_NOT_IMPLEMENTED
) {
1025 bool hasBattery
= false;
1026 rv
= GetHasBattery(&hasBattery
);
1027 if (NS_FAILED(rv
) && rv
!= NS_ERROR_NOT_IMPLEMENTED
) {
1031 uint32_t osBuild
= OperatingSystemBuild();
1033 // Get the adapters once then reuse below
1034 nsAutoString adapterVendorID
[2];
1035 nsAutoString adapterDeviceID
[2];
1036 nsAutoString adapterDriverVendor
[2];
1037 nsAutoString adapterDriverVersionString
[2];
1038 bool adapterInfoFailed
[2];
1040 adapterInfoFailed
[0] =
1041 (NS_FAILED(GetAdapterVendorID(adapterVendorID
[0])) ||
1042 NS_FAILED(GetAdapterDeviceID(adapterDeviceID
[0])) ||
1043 NS_FAILED(GetAdapterDriverVendor(adapterDriverVendor
[0])) ||
1044 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString
[0])));
1045 adapterInfoFailed
[1] =
1046 (NS_FAILED(GetAdapterVendorID2(adapterVendorID
[1])) ||
1047 NS_FAILED(GetAdapterDeviceID2(adapterDeviceID
[1])) ||
1048 NS_FAILED(GetAdapterDriverVendor2(adapterDriverVendor
[1])) ||
1049 NS_FAILED(GetAdapterDriverVersion2(adapterDriverVersionString
[1])));
1050 // No point in going on if we don't have adapter info
1051 if (adapterInfoFailed
[0] && adapterInfoFailed
[1]) {
1055 #if defined(XP_WIN) || defined(ANDROID) || defined(MOZ_WIDGET_GTK)
1056 uint64_t driverVersion
[2] = {0, 0};
1057 if (!adapterInfoFailed
[0]) {
1058 ParseDriverVersion(adapterDriverVersionString
[0], &driverVersion
[0]);
1060 if (!adapterInfoFailed
[1]) {
1061 ParseDriverVersion(adapterDriverVersionString
[1], &driverVersion
[1]);
1066 for (; i
< info
.Length(); i
++) {
1067 // If the status is FEATURE_ALLOW_*, then it is for the allowlist, not
1068 // blocklisting. Only consider entries for our search mode.
1069 if (MatchingAllowStatus(info
[i
].mFeatureStatus
) != aForAllowing
) {
1073 // If we don't have the info for this GPU, no need to check further.
1074 // It is unclear that we would ever have a mixture of 1st and 2nd
1075 // GPU, but leaving the code in for that possibility for now.
1076 // (Actually, currently mGpu2 will never be true, so this can
1077 // be optimized out.)
1078 uint32_t infoIndex
= info
[i
].mGpu2
? 1 : 0;
1079 if (adapterInfoFailed
[infoIndex
]) {
1083 // Do the operating system check first, no point in getting the driver
1084 // info if we won't need to use it.
1085 if (!MatchingOperatingSystems(info
[i
].mOperatingSystem
, os
, osBuild
)) {
1089 if (info
[i
].mOperatingSystemVersion
&&
1090 info
[i
].mOperatingSystemVersion
!= OperatingSystemVersion()) {
1094 if (!MatchingBattery(info
[i
].mBattery
, hasBattery
)) {
1098 if (!MatchingScreenSize(info
[i
].mScreen
, mScreenPixels
)) {
1102 if (!DoesWindowProtocolMatch(info
[i
].mWindowProtocol
, windowProtocol
)) {
1106 if (!DoesVendorMatch(info
[i
].mAdapterVendor
, adapterVendorID
[infoIndex
])) {
1110 if (!DoesDriverVendorMatch(info
[i
].mDriverVendor
,
1111 adapterDriverVendor
[infoIndex
])) {
1115 if (info
[i
].mDevices
&& !info
[i
].mDevices
->IsEmpty()) {
1116 nsresult rv
= info
[i
].mDevices
->Contains(adapterDeviceID
[infoIndex
]);
1117 if (rv
== NS_ERROR_NOT_AVAILABLE
) {
1122 // Failed to search, allowlist should not match, blocklist should match
1123 // for safety reasons
1133 if (!info
[i
].mHardware
.IsEmpty() && !info
[i
].mHardware
.Equals(Hardware())) {
1136 if (!info
[i
].mModel
.IsEmpty() && !info
[i
].mModel
.Equals(Model())) {
1139 if (!info
[i
].mProduct
.IsEmpty() && !info
[i
].mProduct
.Equals(Product())) {
1142 if (!info
[i
].mManufacturer
.IsEmpty() &&
1143 !info
[i
].mManufacturer
.Equals(Manufacturer())) {
1147 #if defined(XP_WIN) || defined(ANDROID) || defined(MOZ_WIDGET_GTK)
1148 switch (info
[i
].mComparisonOp
) {
1149 case DRIVER_LESS_THAN
:
1150 match
= driverVersion
[infoIndex
] < info
[i
].mDriverVersion
;
1152 case DRIVER_BUILD_ID_LESS_THAN
:
1153 match
= (driverVersion
[infoIndex
] & 0xFFFF) < info
[i
].mDriverVersion
;
1155 case DRIVER_LESS_THAN_OR_EQUAL
:
1156 match
= driverVersion
[infoIndex
] <= info
[i
].mDriverVersion
;
1158 case DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL
:
1159 match
= (driverVersion
[infoIndex
] & 0xFFFF) <= info
[i
].mDriverVersion
;
1161 case DRIVER_GREATER_THAN
:
1162 match
= driverVersion
[infoIndex
] > info
[i
].mDriverVersion
;
1164 case DRIVER_GREATER_THAN_OR_EQUAL
:
1165 match
= driverVersion
[infoIndex
] >= info
[i
].mDriverVersion
;
1168 match
= driverVersion
[infoIndex
] == info
[i
].mDriverVersion
;
1170 case DRIVER_NOT_EQUAL
:
1171 match
= driverVersion
[infoIndex
] != info
[i
].mDriverVersion
;
1173 case DRIVER_BETWEEN_EXCLUSIVE
:
1174 match
= driverVersion
[infoIndex
] > info
[i
].mDriverVersion
&&
1175 driverVersion
[infoIndex
] < info
[i
].mDriverVersionMax
;
1177 case DRIVER_BETWEEN_INCLUSIVE
:
1178 match
= driverVersion
[infoIndex
] >= info
[i
].mDriverVersion
&&
1179 driverVersion
[infoIndex
] <= info
[i
].mDriverVersionMax
;
1181 case DRIVER_BETWEEN_INCLUSIVE_START
:
1182 match
= driverVersion
[infoIndex
] >= info
[i
].mDriverVersion
&&
1183 driverVersion
[infoIndex
] < info
[i
].mDriverVersionMax
;
1185 case DRIVER_COMPARISON_IGNORED
:
1186 // We don't have a comparison op, so we match everything.
1190 NS_WARNING("Bogus op in GfxDriverInfo");
1194 // We don't care what driver version it was. We only check OS version and if
1195 // the device matches.
1199 if (match
|| info
[i
].mDriverVersion
== GfxDriverInfo::allDriverVersions
) {
1200 if (info
[i
].mFeature
== GfxDriverInfo::allFeatures
||
1201 info
[i
].mFeature
== aFeature
||
1202 (info
[i
].mFeature
== GfxDriverInfo::optionalFeatures
&&
1203 OnlyAllowFeatureOnKnownConfig(aFeature
))) {
1204 status
= info
[i
].mFeatureStatus
;
1205 if (!info
[i
].mRuleId
.IsEmpty()) {
1206 aFailureId
= info
[i
].mRuleId
.get();
1208 aFailureId
= "FEATURE_FAILURE_DL_BLOCKLIST_NO_ID";
1216 // As a very special case, we block D2D on machines with an NVidia 310M GPU
1217 // as either the primary or secondary adapter. D2D is also blocked when the
1218 // NV 310M is the primary adapter (using the standard blocklisting mechanism).
1219 // If the primary GPU already matched something in the blocklist then we
1220 // ignore this special rule. See bug 1008759.
1221 if (status
== nsIGfxInfo::FEATURE_STATUS_UNKNOWN
&&
1222 (aFeature
== nsIGfxInfo::FEATURE_DIRECT2D
)) {
1223 if (!adapterInfoFailed
[1]) {
1224 nsAString
& nvVendorID
=
1225 (nsAString
&)GfxDriverInfo::GetDeviceVendor(DeviceVendor::NVIDIA
);
1226 const nsString nv310mDeviceId
= u
"0x0A70"_ns
;
1227 if (nvVendorID
.Equals(adapterVendorID
[1],
1228 nsCaseInsensitiveStringComparator
) &&
1229 nv310mDeviceId
.Equals(adapterDeviceID
[1],
1230 nsCaseInsensitiveStringComparator
)) {
1231 status
= nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
1232 aFailureId
= "FEATURE_FAILURE_D2D_NV310M_BLOCK";
1237 // Depends on Windows driver versioning. We don't pass a GfxDriverInfo object
1238 // back to the Windows handler, so we must handle this here.
1239 if (status
== FEATURE_BLOCKED_DRIVER_VERSION
) {
1240 if (info
[i
].mSuggestedVersion
) {
1241 aSuggestedVersion
.AppendPrintf("%s", info
[i
].mSuggestedVersion
);
1242 } else if (info
[i
].mComparisonOp
== DRIVER_LESS_THAN
&&
1243 info
[i
].mDriverVersion
!= GfxDriverInfo::allDriverVersions
) {
1244 aSuggestedVersion
.AppendPrintf(
1245 "%lld.%lld.%lld.%lld",
1246 (info
[i
].mDriverVersion
& 0xffff000000000000) >> 48,
1247 (info
[i
].mDriverVersion
& 0x0000ffff00000000) >> 32,
1248 (info
[i
].mDriverVersion
& 0x00000000ffff0000) >> 16,
1249 (info
[i
].mDriverVersion
& 0x000000000000ffff));
1257 void GfxInfoBase::SetFeatureStatus(nsTArray
<gfx::GfxInfoFeatureStatus
>&& aFS
) {
1258 MOZ_ASSERT(!sFeatureStatus
);
1259 InitFeatureStatus(new nsTArray
<gfx::GfxInfoFeatureStatus
>(std::move(aFS
)));
1262 bool GfxInfoBase::DoesWindowProtocolMatch(
1263 const nsAString
& aBlocklistWindowProtocol
,
1264 const nsAString
& aWindowProtocol
) {
1265 return aBlocklistWindowProtocol
.Equals(aWindowProtocol
,
1266 nsCaseInsensitiveStringComparator
) ||
1267 aBlocklistWindowProtocol
.Equals(
1268 GfxDriverInfo::GetWindowProtocol(WindowProtocol::All
),
1269 nsCaseInsensitiveStringComparator
);
1272 bool GfxInfoBase::DoesVendorMatch(const nsAString
& aBlocklistVendor
,
1273 const nsAString
& aAdapterVendor
) {
1274 return aBlocklistVendor
.Equals(aAdapterVendor
,
1275 nsCaseInsensitiveStringComparator
) ||
1276 aBlocklistVendor
.Equals(
1277 GfxDriverInfo::GetDeviceVendor(DeviceVendor::All
),
1278 nsCaseInsensitiveStringComparator
);
1281 bool GfxInfoBase::DoesDriverVendorMatch(const nsAString
& aBlocklistVendor
,
1282 const nsAString
& aDriverVendor
) {
1283 return aBlocklistVendor
.Equals(aDriverVendor
,
1284 nsCaseInsensitiveStringComparator
) ||
1285 aBlocklistVendor
.Equals(
1286 GfxDriverInfo::GetDriverVendor(DriverVendor::All
),
1287 nsCaseInsensitiveStringComparator
);
1290 bool GfxInfoBase::IsFeatureAllowlisted(int32_t aFeature
) const {
1291 return aFeature
== nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY
;
1294 nsresult
GfxInfoBase::GetFeatureStatusImpl(
1295 int32_t aFeature
, int32_t* aStatus
, nsAString
& aSuggestedVersion
,
1296 const nsTArray
<GfxDriverInfo
>& aDriverInfo
, nsACString
& aFailureId
,
1297 OperatingSystem
* aOS
/* = nullptr */) {
1298 if (aFeature
<= 0) {
1299 gfxWarning() << "Invalid feature <= 0";
1303 if (*aStatus
!= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
) {
1304 // Terminate now with the status determined by the derived type (OS-specific
1309 if (sShutdownOccurred
) {
1310 // This is futile; we've already commenced shutdown and our blocklists have
1311 // been deleted. We may want to look into resurrecting the blocklist instead
1312 // but for now, just don't even go there.
1316 // Ensure any additional initialization required is complete.
1319 // If an operating system was provided by the derived GetFeatureStatusImpl,
1320 // grab it here. Otherwise, the OS is unknown.
1321 OperatingSystem os
= (aOS
? *aOS
: OperatingSystem::Unknown
);
1323 nsAutoString adapterVendorID
;
1324 nsAutoString adapterDeviceID
;
1325 nsAutoString adapterDriverVersionString
;
1326 if (NS_FAILED(GetAdapterVendorID(adapterVendorID
)) ||
1327 NS_FAILED(GetAdapterDeviceID(adapterDeviceID
)) ||
1328 NS_FAILED(GetAdapterDriverVersion(adapterDriverVersionString
))) {
1329 if (OnlyAllowFeatureOnKnownConfig(aFeature
)) {
1330 aFailureId
= "FEATURE_FAILURE_CANT_RESOLVE_ADAPTER";
1331 *aStatus
= nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
1333 *aStatus
= nsIGfxInfo::FEATURE_STATUS_OK
;
1338 // We only check either the given blocklist, or the static list, as given.
1340 if (aDriverInfo
.Length()) {
1342 FindBlocklistedDeviceInList(aDriverInfo
, aSuggestedVersion
, aFeature
,
1343 aFailureId
, os
, /* aForAllowing */ false);
1346 sDriverInfo
= new nsTArray
<GfxDriverInfo
>();
1348 status
= FindBlocklistedDeviceInList(GetGfxDriverInfo(), aSuggestedVersion
,
1349 aFeature
, aFailureId
, os
,
1350 /* aForAllowing */ false);
1353 if (status
== nsIGfxInfo::FEATURE_STATUS_UNKNOWN
) {
1354 if (IsFeatureAllowlisted(aFeature
)) {
1355 // This feature is actually using the allowlist; that means after we pass
1356 // the blocklist to prevent us explicitly from getting the feature, we now
1357 // need to check the allowlist to ensure we are allowed to get it in the
1359 if (aDriverInfo
.Length()) {
1360 status
= FindBlocklistedDeviceInList(aDriverInfo
, aSuggestedVersion
,
1361 aFeature
, aFailureId
, os
,
1362 /* aForAllowing */ true);
1364 status
= FindBlocklistedDeviceInList(
1365 GetGfxDriverInfo(), aSuggestedVersion
, aFeature
, aFailureId
, os
,
1366 /* aForAllowing */ true);
1369 if (status
== nsIGfxInfo::FEATURE_STATUS_UNKNOWN
) {
1370 status
= nsIGfxInfo::FEATURE_DENIED
;
1373 // It's now done being processed. It's safe to set the status to
1375 status
= nsIGfxInfo::FEATURE_STATUS_OK
;
1384 GfxInfoBase::GetFeatureSuggestedDriverVersion(int32_t aFeature
,
1385 nsAString
& aVersion
) {
1387 if (GetPrefValueForDriverVersion(version
)) {
1388 aVersion
= NS_ConvertASCIItoUTF16(version
);
1393 nsCString discardFailureId
;
1394 nsTArray
<GfxDriverInfo
> driverInfo
;
1395 return GetFeatureStatusImpl(aFeature
, &status
, aVersion
, driverInfo
,
1399 void GfxInfoBase::EvaluateDownloadedBlocklist(
1400 nsTArray
<GfxDriverInfo
>& aDriverInfo
) {
1401 // If the list is empty, then we don't actually want to call
1402 // GetFeatureStatusImpl since we will use the static list instead. In that
1403 // case, all we want to do is make sure the pref is removed.
1404 if (aDriverInfo
.IsEmpty()) {
1405 gfxCriticalNoteOnce
<< "Evaluate empty downloaded blocklist";
1409 OperatingSystem os
= GetOperatingSystem();
1411 // For every feature we know about, we evaluate whether this blocklist has a
1412 // non-STATUS_OK status. If it does, we set the pref we evaluate in
1413 // GetFeatureStatus above, so we don't need to hold on to this blocklist
1414 // anywhere permanent.
1415 for (int feature
= 1; feature
<= nsIGfxInfo::FEATURE_MAX_VALUE
; ++feature
) {
1416 int32_t status
= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
;
1417 nsCString failureId
;
1418 nsAutoString suggestedVersion
;
1420 // Note that we are careful to call the base class method since we only want
1421 // to evaluate the downloadable blocklist for these prefs.
1422 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(GfxInfoBase::GetFeatureStatusImpl(
1423 feature
, &status
, suggestedVersion
, aDriverInfo
, failureId
, &os
)));
1427 MOZ_FALLTHROUGH_ASSERT("Unhandled feature status!");
1428 case nsIGfxInfo::FEATURE_STATUS_UNKNOWN
:
1429 // This may be returned during shutdown or for invalid features.
1430 case nsIGfxInfo::FEATURE_ALLOW_ALWAYS
:
1431 case nsIGfxInfo::FEATURE_ALLOW_QUALIFIED
:
1432 case nsIGfxInfo::FEATURE_DENIED
:
1433 // We cannot use the downloadable blocklist to control the allowlist.
1434 // If a feature is allowlisted, then we should also ignore DENIED
1435 // statuses from GetFeatureStatusImpl because we don't check the
1436 // static list when and this is an expected value. If we wish to
1437 // override the allowlist, it is as simple as creating a normal
1438 // blocklist rule with a BLOCKED* status code.
1439 case nsIGfxInfo::FEATURE_STATUS_OK
:
1440 RemovePrefForFeature(feature
);
1443 case nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
:
1444 if (!suggestedVersion
.IsEmpty()) {
1445 SetPrefValueForDriverVersion(suggestedVersion
);
1447 RemovePrefForDriverVersion();
1451 case nsIGfxInfo::FEATURE_BLOCKED_MISMATCHED_VERSION
:
1452 case nsIGfxInfo::FEATURE_BLOCKED_DEVICE
:
1453 case nsIGfxInfo::FEATURE_DISCOURAGED
:
1454 case nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION
:
1455 case nsIGfxInfo::FEATURE_BLOCKED_PLATFORM_TEST
:
1456 SetPrefValueForFeature(feature
, status
, failureId
);
1462 NS_IMETHODIMP_(void)
1463 GfxInfoBase::LogFailure(const nsACString
& failure
) {
1464 // gfxCriticalError has a mutex lock of its own, so we may not actually
1465 // need this lock. ::GetFailures() accesses the data but the LogForwarder
1466 // will not return the copy of the logs unless it can get the same lock
1467 // that gfxCriticalError uses. Still, that is so much of an implementation
1468 // detail that it's nicer to just add an extra lock here and in
1470 MutexAutoLock
lock(mMutex
);
1472 // By default, gfxCriticalError asserts; make it not assert in this case.
1473 gfxCriticalError(CriticalLog::DefaultOptions(false))
1474 << "(LF) " << failure
.BeginReading();
1477 NS_IMETHODIMP
GfxInfoBase::GetFailures(nsTArray
<int32_t>& indices
,
1478 nsTArray
<nsCString
>& failures
) {
1479 MutexAutoLock
lock(mMutex
);
1481 LogForwarder
* logForwarder
= Factory::GetLogForwarder();
1482 if (!logForwarder
) {
1483 return NS_ERROR_UNEXPECTED
;
1486 // There are two string copies in this method, starting with this one. We are
1487 // assuming this is not a big deal, as the size of the array should be small
1488 // and the strings in it should be small as well (the error messages in the
1489 // code.) The second copy happens with the AppendElement() calls.
1490 // Technically, we don't need the mutex lock after the StringVectorCopy()
1492 LoggingRecord loggedStrings
= logForwarder
->LoggingRecordCopy();
1493 LoggingRecord::const_iterator it
;
1494 for (it
= loggedStrings
.begin(); it
!= loggedStrings
.end(); ++it
) {
1495 failures
.AppendElement(nsDependentCSubstring(std::get
<1>(*it
).c_str(),
1496 std::get
<1>(*it
).size()));
1497 indices
.AppendElement(std::get
<0>(*it
));
1503 nsTArray
<GfxInfoCollectorBase
*>* sCollectors
;
1505 static void InitCollectors() {
1506 if (!sCollectors
) sCollectors
= new nsTArray
<GfxInfoCollectorBase
*>;
1509 nsresult
GfxInfoBase::GetInfo(JSContext
* aCx
,
1510 JS::MutableHandle
<JS::Value
> aResult
) {
1512 InfoObject
obj(aCx
);
1514 for (uint32_t i
= 0; i
< sCollectors
->Length(); i
++) {
1515 (*sCollectors
)[i
]->GetInfo(obj
);
1518 // Some example property definitions
1519 // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
1520 // obj.DefineProperty("renderer", mRendererIDsString);
1521 // obj.DefineProperty("five", 5);
1524 return NS_ERROR_FAILURE
;
1527 aResult
.setObject(*obj
.mObj
);
1531 nsAutoCString gBaseAppVersion
;
1533 const nsCString
& GfxInfoBase::GetApplicationVersion() {
1534 static bool versionInitialized
= false;
1535 if (!versionInitialized
) {
1536 // If we fail to get the version, we will not try again.
1537 versionInitialized
= true;
1539 // Get the version from xpcom/system/nsIXULAppInfo.idl
1540 nsCOMPtr
<nsIXULAppInfo
> app
= do_GetService("@mozilla.org/xre/app-info;1");
1542 app
->GetVersion(gBaseAppVersion
);
1545 return gBaseAppVersion
;
1548 /* static */ bool GfxInfoBase::OnlyAllowFeatureOnKnownConfig(int32_t aFeature
) {
1550 // The GPU process doesn't need hardware acceleration and can run on
1551 // devices that we normally block from not being on our whitelist.
1552 case nsIGfxInfo::FEATURE_GPU_PROCESS
:
1554 // We can mostly assume that ANGLE will work
1555 case nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE
:
1556 // Remote WebGL is needed for Win32k Lockdown, so it should be enabled
1557 // regardless of HW support or not
1558 case nsIGfxInfo::FEATURE_ALLOW_WEBGL_OUT_OF_PROCESS
:
1559 // Backdrop filter should generally work, especially if we fall back to
1560 // Software WebRender because of an unknown vendor.
1561 case nsIGfxInfo::FEATURE_BACKDROP_FILTER
:
1568 void GfxInfoBase::AddCollector(GfxInfoCollectorBase
* collector
) {
1570 sCollectors
->AppendElement(collector
);
1573 void GfxInfoBase::RemoveCollector(GfxInfoCollectorBase
* collector
) {
1575 for (uint32_t i
= 0; i
< sCollectors
->Length(); i
++) {
1576 if ((*sCollectors
)[i
] == collector
) {
1577 sCollectors
->RemoveElementAt(i
);
1581 if (sCollectors
->IsEmpty()) {
1583 sCollectors
= nullptr;
1587 static void AppendMonitor(JSContext
* aCx
, widget::Screen
& aScreen
,
1588 JS::Handle
<JSObject
*> aOutArray
, int32_t aIndex
) {
1589 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1591 auto screenSize
= aScreen
.GetRect().Size();
1593 JS::Rooted
<JS::Value
> screenWidth(aCx
, JS::Int32Value(screenSize
.width
));
1594 JS_SetProperty(aCx
, obj
, "screenWidth", screenWidth
);
1596 JS::Rooted
<JS::Value
> screenHeight(aCx
, JS::Int32Value(screenSize
.height
));
1597 JS_SetProperty(aCx
, obj
, "screenHeight", screenHeight
);
1599 // XXX Just preserving behavior since this is exposed to telemetry, but we
1600 // could consider including this everywhere.
1602 JS::Rooted
<JS::Value
> scale(
1603 aCx
, JS::NumberValue(aScreen
.GetContentsScaleFactor()));
1604 JS_SetProperty(aCx
, obj
, "scale", scale
);
1608 JS::Rooted
<JS::Value
> refreshRate(aCx
,
1609 JS::Int32Value(aScreen
.GetRefreshRate()));
1610 JS_SetProperty(aCx
, obj
, "refreshRate", refreshRate
);
1612 JS::Rooted
<JS::Value
> pseudoDisplay(
1613 aCx
, JS::BooleanValue(aScreen
.GetIsPseudoDisplay()));
1614 JS_SetProperty(aCx
, obj
, "pseudoDisplay", pseudoDisplay
);
1617 JS::Rooted
<JS::Value
> element(aCx
, JS::ObjectValue(*obj
));
1618 JS_SetElement(aCx
, aOutArray
, aIndex
, element
);
1621 nsresult
GfxInfoBase::FindMonitors(JSContext
* aCx
,
1622 JS::Handle
<JSObject
*> aOutArray
) {
1624 auto& sm
= ScreenManager::GetSingleton();
1625 for (auto& screen
: sm
.CurrentScreenList()) {
1626 AppendMonitor(aCx
, *screen
, aOutArray
, index
++);
1630 // Ensure we return at least one monitor, this is needed for xpcshell.
1631 RefPtr
<Screen
> screen
= sm
.GetPrimaryScreen();
1632 AppendMonitor(aCx
, *screen
, aOutArray
, index
++);
1639 GfxInfoBase::GetMonitors(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aResult
) {
1640 JS::Rooted
<JSObject
*> array(aCx
, JS::NewArrayObject(aCx
, 0));
1642 nsresult rv
= FindMonitors(aCx
, array
);
1643 if (NS_FAILED(rv
)) {
1647 aResult
.setObject(*array
);
1651 static inline bool SetJSPropertyString(JSContext
* aCx
,
1652 JS::Handle
<JSObject
*> aObj
,
1653 const char* aProp
, const char* aString
) {
1654 JS::Rooted
<JSString
*> str(aCx
, JS_NewStringCopyZ(aCx
, aString
));
1659 JS::Rooted
<JS::Value
> val(aCx
, JS::StringValue(str
));
1660 return JS_SetProperty(aCx
, aObj
, aProp
, val
);
1663 template <typename T
>
1664 static inline bool AppendJSElement(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
1667 if (!JS::GetArrayLength(aCx
, aObj
, &index
)) {
1670 return JS_SetElement(aCx
, aObj
, index
, aValue
);
1673 nsresult
GfxInfoBase::GetFeatures(JSContext
* aCx
,
1674 JS::MutableHandle
<JS::Value
> aOut
) {
1675 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1677 return NS_ERROR_OUT_OF_MEMORY
;
1679 aOut
.setObject(*obj
);
1681 layers::LayersBackend backend
=
1682 gfxPlatform::Initialized()
1683 ? gfxPlatform::GetPlatform()->GetCompositorBackend()
1684 : layers::LayersBackend::LAYERS_NONE
;
1685 const char* backendName
= layers::GetLayersBackendName(backend
);
1686 SetJSPropertyString(aCx
, obj
, "compositor", backendName
);
1688 // If graphics isn't initialized yet, just stop now.
1689 if (!gfxPlatform::Initialized()) {
1693 DescribeFeatures(aCx
, obj
);
1697 nsresult
GfxInfoBase::GetFeatureLog(JSContext
* aCx
,
1698 JS::MutableHandle
<JS::Value
> aOut
) {
1699 JS::Rooted
<JSObject
*> containerObj(aCx
, JS_NewPlainObject(aCx
));
1700 if (!containerObj
) {
1701 return NS_ERROR_OUT_OF_MEMORY
;
1703 aOut
.setObject(*containerObj
);
1705 JS::Rooted
<JSObject
*> featureArray(aCx
, JS::NewArrayObject(aCx
, 0));
1706 if (!featureArray
) {
1707 return NS_ERROR_OUT_OF_MEMORY
;
1710 // Collect features.
1711 gfxConfig::ForEachFeature([&](const char* aName
, const char* aDescription
,
1712 FeatureState
& aFeature
) -> void {
1713 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1717 if (!SetJSPropertyString(aCx
, obj
, "name", aName
) ||
1718 !SetJSPropertyString(aCx
, obj
, "description", aDescription
) ||
1719 !SetJSPropertyString(aCx
, obj
, "status",
1720 FeatureStatusToString(aFeature
.GetValue()))) {
1724 JS::Rooted
<JS::Value
> log(aCx
);
1725 if (!BuildFeatureStateLog(aCx
, aFeature
, &log
)) {
1728 if (!JS_SetProperty(aCx
, obj
, "log", log
)) {
1732 if (!AppendJSElement(aCx
, featureArray
, obj
)) {
1737 JS::Rooted
<JSObject
*> fallbackArray(aCx
, JS::NewArrayObject(aCx
, 0));
1738 if (!fallbackArray
) {
1739 return NS_ERROR_OUT_OF_MEMORY
;
1742 // Collect fallbacks.
1743 gfxConfig::ForEachFallback(
1744 [&](const char* aName
, const char* aMessage
) -> void {
1745 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1750 if (!SetJSPropertyString(aCx
, obj
, "name", aName
) ||
1751 !SetJSPropertyString(aCx
, obj
, "message", aMessage
)) {
1755 if (!AppendJSElement(aCx
, fallbackArray
, obj
)) {
1760 JS::Rooted
<JS::Value
> val(aCx
);
1762 val
= JS::ObjectValue(*featureArray
);
1763 JS_SetProperty(aCx
, containerObj
, "features", val
);
1765 val
= JS::ObjectValue(*fallbackArray
);
1766 JS_SetProperty(aCx
, containerObj
, "fallbacks", val
);
1771 bool GfxInfoBase::BuildFeatureStateLog(JSContext
* aCx
,
1772 const FeatureState
& aFeature
,
1773 JS::MutableHandle
<JS::Value
> aOut
) {
1774 JS::Rooted
<JSObject
*> log(aCx
, JS::NewArrayObject(aCx
, 0));
1778 aOut
.setObject(*log
);
1780 aFeature
.ForEachStatusChange([&](const char* aType
, FeatureStatus aStatus
,
1781 const char* aMessage
,
1782 const nsCString
& aFailureId
) -> void {
1783 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1788 if (!SetJSPropertyString(aCx
, obj
, "type", aType
) ||
1789 !SetJSPropertyString(aCx
, obj
, "status",
1790 FeatureStatusToString(aStatus
)) ||
1791 (!aFailureId
.IsEmpty() &&
1792 !SetJSPropertyString(aCx
, obj
, "failureId", aFailureId
.get())) ||
1793 (aMessage
&& !SetJSPropertyString(aCx
, obj
, "message", aMessage
))) {
1797 if (!AppendJSElement(aCx
, log
, obj
)) {
1805 void GfxInfoBase::DescribeFeatures(JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
) {
1806 JS::Rooted
<JSObject
*> obj(aCx
);
1808 gfx::FeatureState
& hwCompositing
=
1809 gfxConfig::GetFeature(gfx::Feature::HW_COMPOSITING
);
1810 InitFeatureObject(aCx
, aObj
, "hwCompositing", hwCompositing
, &obj
);
1812 gfx::FeatureState
& gpuProcess
=
1813 gfxConfig::GetFeature(gfx::Feature::GPU_PROCESS
);
1814 InitFeatureObject(aCx
, aObj
, "gpuProcess", gpuProcess
, &obj
);
1816 gfx::FeatureState
& webrender
= gfxConfig::GetFeature(gfx::Feature::WEBRENDER
);
1817 InitFeatureObject(aCx
, aObj
, "webrender", webrender
, &obj
);
1819 gfx::FeatureState
& wrCompositor
=
1820 gfxConfig::GetFeature(gfx::Feature::WEBRENDER_COMPOSITOR
);
1821 InitFeatureObject(aCx
, aObj
, "wrCompositor", wrCompositor
, &obj
);
1823 gfx::FeatureState
& openglCompositing
=
1824 gfxConfig::GetFeature(gfx::Feature::OPENGL_COMPOSITING
);
1825 InitFeatureObject(aCx
, aObj
, "openglCompositing", openglCompositing
, &obj
);
1827 gfx::FeatureState
& omtp
= gfxConfig::GetFeature(gfx::Feature::OMTP
);
1828 InitFeatureObject(aCx
, aObj
, "omtp", omtp
, &obj
);
1831 bool GfxInfoBase::InitFeatureObject(JSContext
* aCx
,
1832 JS::Handle
<JSObject
*> aContainer
,
1834 mozilla::gfx::FeatureState
& aFeatureState
,
1835 JS::MutableHandle
<JSObject
*> aOutObj
) {
1836 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1841 nsCString status
= aFeatureState
.GetStatusAndFailureIdString();
1843 JS::Rooted
<JSString
*> str(aCx
, JS_NewStringCopyZ(aCx
, status
.get()));
1844 JS::Rooted
<JS::Value
> val(aCx
, JS::StringValue(str
));
1845 JS_SetProperty(aCx
, obj
, "status", val
);
1847 // Add the feature object to the container.
1849 JS::Rooted
<JS::Value
> val(aCx
, JS::ObjectValue(*obj
));
1850 JS_SetProperty(aCx
, aContainer
, aName
, val
);
1857 nsresult
GfxInfoBase::GetActiveCrashGuards(JSContext
* aCx
,
1858 JS::MutableHandle
<JS::Value
> aOut
) {
1859 JS::Rooted
<JSObject
*> array(aCx
, JS::NewArrayObject(aCx
, 0));
1861 return NS_ERROR_OUT_OF_MEMORY
;
1863 aOut
.setObject(*array
);
1865 DriverCrashGuard::ForEachActiveCrashGuard(
1866 [&](const char* aName
, const char* aPrefName
) -> void {
1867 JS::Rooted
<JSObject
*> obj(aCx
, JS_NewPlainObject(aCx
));
1871 if (!SetJSPropertyString(aCx
, obj
, "type", aName
)) {
1874 if (!SetJSPropertyString(aCx
, obj
, "prefName", aPrefName
)) {
1877 if (!AppendJSElement(aCx
, array
, obj
)) {
1886 GfxInfoBase::GetTargetFrameRate(uint32_t* aTargetFrameRate
) {
1887 *aTargetFrameRate
= gfxPlatform::TargetFrameRate();
1892 GfxInfoBase::GetCodecSupportInfo(nsACString
& aCodecSupportInfo
) {
1893 aCodecSupportInfo
.Assign(gfx::gfxVars::CodecSupportInfo());
1898 GfxInfoBase::GetIsHeadless(bool* aIsHeadless
) {
1899 *aIsHeadless
= gfxPlatform::IsHeadless();
1903 #if defined(MOZ_WIDGET_ANDROID)
1905 const char* chromebookProductList
[] = {
1906 "asuka", "asurada", "atlas", "auron", "banjo", "banon",
1907 "bob", "brask", "brya", "buddy", "butterfly", "candy",
1908 "caroline", "cave", "celes", "chell", "cherry", "clapper",
1909 "coral", "corsola", "cyan", "daisy", "dedede", "drallion",
1910 "edgar", "elm", "enguarde", "eve", "expresso", "falco",
1911 "fizz", "gandof", "glimmer", "gnawty", "grunt", "guado",
1912 "guybrush", "hana", "hatch", "heli", "jacuzzi", "kalista",
1913 "kefka", "kevin", "kip", "kukui", "lars", "leon",
1914 "link", "lulu", "lumpy", "mccloud", "monroe", "nami",
1915 "nautilus", "ninja", "nissa", "nocturne", "nyan", "octopus",
1916 "orco", "panther", "parrot", "peach", "peppy", "puff",
1917 "pyro", "quawks", "rammus", "reef", "reks", "relm",
1918 "rikku", "samus", "sand", "sarien", "scarlet", "sentry",
1919 "setzer", "skyrim", "snappy", "soraka", "squawks", "staryu",
1920 "stout", "strongbad", "stumpy", "sumo", "swanky", "terra",
1921 "tidus", "tricky", "trogdor", "ultima", "veyron", "volteer",
1922 "winky", "wizpig", "wolf", "x86", "zako", "zork"};
1924 bool ProductIsChromebook(nsCString product
) {
1926 return BinarySearchIf(
1927 chromebookProductList
, 0, ArrayLength(chromebookProductList
),
1928 [&](const char* const aValue
) -> int {
1929 return strcmp(product
.get(), aValue
);
1935 using Device
= nsIGfxInfo::FontVisibilityDeviceDetermination
;
1936 static StaticAutoPtr
<std::pair
<Device
, nsString
>> ret
;
1938 std::pair
<Device
, nsString
>* GfxInfoBase::GetFontVisibilityDeterminationPair() {
1940 ret
= new std::pair
<Device
, nsString
>();
1941 ret
->first
= Device::Unassigned
;
1942 ret
->second
= u
""_ns
;
1943 ClearOnShutdown(&ret
);
1946 if (ret
->first
!= Device::Unassigned
) {
1950 #if defined(MOZ_WIDGET_ANDROID)
1951 auto androidReleaseVersion
= strtol(
1952 java::sdk::Build::VERSION::RELEASE()->ToCString().get(), nullptr, 10);
1954 auto androidManufacturer
= java::sdk::Build::MANUFACTURER()->ToCString();
1955 nsContentUtils::ASCIIToLower(androidManufacturer
);
1957 auto androidBrand
= java::sdk::Build::BRAND()->ToCString();
1958 nsContentUtils::ASCIIToLower(androidBrand
);
1960 auto androidModel
= java::sdk::Build::MODEL()->ToCString();
1961 nsContentUtils::ASCIIToLower(androidModel
);
1963 auto androidProduct
= java::sdk::Build::PRODUCT()->ToCString();
1964 nsContentUtils::ASCIIToLower(androidProduct
);
1966 auto androidProductIsChromebook
= ProductIsChromebook(androidProduct
);
1968 if (androidReleaseVersion
< 4 || androidReleaseVersion
> 20) {
1969 // Something is screwy, oh well.
1970 ret
->second
.AppendASCII("Unknown Release Version - ");
1971 ret
->first
= Device::Android_Unknown_Release_Version
;
1972 } else if (androidReleaseVersion
<= 8) {
1973 ret
->second
.AppendASCII("Android <9 - ");
1974 ret
->first
= Device::Android_sub_9
;
1975 } else if (androidReleaseVersion
<= 11) {
1976 ret
->second
.AppendASCII("Android 9-11 - ");
1977 ret
->first
= Device::Android_9_11
;
1978 } else if (androidReleaseVersion
> 11) {
1979 ret
->second
.AppendASCII("Android 12+ - ");
1980 ret
->first
= Device::Android_12_plus
;
1982 MOZ_CRASH_UNSAFE_PRINTF(
1983 "Somehow wound up in GetFontVisibilityDeterminationPair with a release "
1985 androidReleaseVersion
);
1988 if (androidManufacturer
== "google" && androidModel
== androidProduct
&&
1989 androidProductIsChromebook
) {
1990 // Chromebook font set coming later
1991 ret
->second
.AppendASCII("Chromebook - ");
1992 ret
->first
= Device::Android_Chromebook
;
1994 if (androidBrand
== "amazon") {
1995 // Amazon Fire font set coming later
1996 ret
->second
.AppendASCII("Amazon - ");
1997 ret
->first
= Device::Android_Amazon
;
1999 if (androidBrand
== "peloton") {
2000 // We don't know how to categorize fonts on this system
2001 ret
->second
.AppendASCII("Peloton - ");
2002 ret
->first
= Device::Android_Unknown_Peloton
;
2004 if (androidProduct
== "vbox86p") {
2005 ret
->second
.AppendASCII("vbox - ");
2006 // We can't categorize fonts when running in an emulator on a Desktop
2007 ret
->first
= Device::Android_Unknown_vbox
;
2009 if (androidModel
.Find("mitv"_ns
) != kNotFound
&& androidBrand
== "xiaomi") {
2010 // We don't know how to categorize fonts on this system
2011 ret
->second
.AppendASCII("mitv - ");
2012 ret
->first
= Device::Android_Unknown_mitv
;
2015 ret
->second
.AppendPrintf(
2016 "release_version_str=%s, release_version=%li",
2017 java::sdk::Build::VERSION::RELEASE()->ToCString().get(),
2018 androidReleaseVersion
);
2019 ret
->second
.AppendPrintf(
2020 ", manufacturer=%s, brand=%s, model=%s, product=%s, chromebook=%s",
2021 androidManufacturer
.get(), androidBrand
.get(), androidModel
.get(),
2022 androidProduct
.get(), androidProductIsChromebook
? "yes" : "no");
2024 #elif defined(XP_LINUX)
2025 ret
->first
= Device::Linux_Unknown
;
2027 long versionMajor
= 0;
2028 FILE* fp
= fopen("/etc/os-release", "r");
2031 while (fgets(buf
, sizeof(buf
), fp
)) {
2032 if (strncmp(buf
, "VERSION_ID=\"", 12) == 0) {
2033 ret
->second
.AppendPrintf("VERSION_ID=%.11s", buf
+ 11);
2034 versionMajor
= strtol(buf
+ 12, nullptr, 10);
2035 if (ret
->first
!= Device::Linux_Unknown
) {
2040 if (strncmp(buf
, "ID=", 3) == 0) {
2041 ret
->second
.AppendPrintf("ID=%.6s", buf
+ 3);
2042 if (strncmp(buf
+ 3, "ubuntu", 6) == 0) {
2043 ret
->first
= Device::Linux_Ubuntu_any
;
2044 } else if (strncmp(buf
+ 3, "fedora", 6) == 0) {
2045 ret
->first
= Device::Linux_Fedora_any
;
2055 if (ret
->first
== Device::Linux_Ubuntu_any
) {
2056 if (versionMajor
== 20) {
2057 ret
->first
= Device::Linux_Ubuntu_20
;
2058 ret
->second
.Insert(u
"Ubuntu 20 - ", 0);
2059 } else if (versionMajor
== 22) {
2060 ret
->first
= Device::Linux_Ubuntu_22
;
2061 ret
->second
.Insert(u
"Ubuntu 22 - ", 0);
2063 ret
->second
.Insert(u
"Ubuntu Unknown - ", 0);
2065 } else if (ret
->first
== Device::Linux_Fedora_any
) {
2066 if (versionMajor
== 38) {
2067 ret
->first
= Device::Linux_Fedora_38
;
2068 ret
->second
.Insert(u
"Fedora 38 - ", 0);
2069 } else if (versionMajor
== 39) {
2070 ret
->first
= Device::Linux_Fedora_39
;
2071 ret
->second
.Insert(u
"Fedora 39 - ", 0);
2073 ret
->second
.Insert(u
"Fedora Unknown - ", 0);
2076 ret
->second
.Insert(u
"Linux Unknown - ", 0);
2079 #elif defined(XP_MACOSX)
2080 ret
->first
= Device::MacOS_Platform
;
2081 ret
->second
.AppendASCII("macOS Platform");
2082 #elif defined(XP_WIN)
2083 ret
->first
= Device::Windows_Platform
;
2084 ret
->second
.AppendASCII("Windows Platform");
2086 ret
->first
= Device::Unknown_Platform
;
2087 ret
->second
.AppendASCII("Unknown Platform");
2094 GfxInfoBase::GetFontVisibilityDetermination(
2095 Device
* aFontVisibilityDetermination
) {
2096 auto ret
= GetFontVisibilityDeterminationPair();
2098 *aFontVisibilityDetermination
= ret
->first
;
2103 GfxInfoBase::GetFontVisibilityDeterminationStr(
2104 nsAString
& aFontVisibilityDeterminationStr
) {
2105 auto ret
= GetFontVisibilityDeterminationPair();
2106 aFontVisibilityDeterminationStr
.Assign(ret
->second
);
2111 GfxInfoBase::GetContentBackend(nsAString
& aContentBackend
) {
2112 BackendType backend
= gfxPlatform::GetPlatform()->GetDefaultContentBackend();
2116 case BackendType::DIRECT2D1_1
: {
2117 outStr
.AppendPrintf("Direct2D 1.1");
2120 case BackendType::SKIA
: {
2121 outStr
.AppendPrintf("Skia");
2124 case BackendType::CAIRO
: {
2125 outStr
.AppendPrintf("Cairo");
2129 return NS_ERROR_FAILURE
;
2132 aContentBackend
.Assign(outStr
);
2137 GfxInfoBase::GetAzureCanvasBackend(nsAString
& aBackend
) {
2138 CopyASCIItoUTF16(mozilla::MakeStringSpan(
2139 gfxPlatform::GetPlatform()->GetAzureCanvasBackend()),
2145 GfxInfoBase::GetAzureContentBackend(nsAString
& aBackend
) {
2146 CopyASCIItoUTF16(mozilla::MakeStringSpan(
2147 gfxPlatform::GetPlatform()->GetAzureContentBackend()),
2153 GfxInfoBase::GetUsingGPUProcess(bool* aOutValue
) {
2154 GPUProcessManager
* gpu
= GPUProcessManager::Get();
2156 // Not supported in content processes.
2157 return NS_ERROR_FAILURE
;
2160 *aOutValue
= !!gpu
->GetGPUChild();
2164 NS_IMETHODIMP_(int32_t)
2165 GfxInfoBase::GetMaxRefreshRate(bool* aMixed
) {
2170 int32_t maxRefreshRate
= 0;
2171 for (auto& screen
: ScreenManager::GetSingleton().CurrentScreenList()) {
2172 int32_t refreshRate
= screen
->GetRefreshRate();
2173 if (aMixed
&& maxRefreshRate
> 0 && maxRefreshRate
!= refreshRate
) {
2176 maxRefreshRate
= std::max(maxRefreshRate
, refreshRate
);
2179 return maxRefreshRate
> 0 ? maxRefreshRate
: -1;
2183 GfxInfoBase::ControlGPUProcessForXPCShell(bool aEnable
, bool* _retval
) {
2184 gfxPlatform::GetPlatform();
2186 GPUProcessManager
* gpm
= GPUProcessManager::Get();
2188 if (!gfxConfig::IsEnabled(gfx::Feature::GPU_PROCESS
)) {
2189 gfxConfig::UserForceEnable(gfx::Feature::GPU_PROCESS
, "xpcshell-test");
2191 DebugOnly
<nsresult
> rv
= gpm
->EnsureGPUReady();
2192 MOZ_ASSERT(rv
!= NS_ERROR_ILLEGAL_DURING_SHUTDOWN
);
2194 gfxConfig::UserDisable(gfx::Feature::GPU_PROCESS
, "xpcshell-test");
2202 NS_IMETHODIMP
GfxInfoBase::KillGPUProcessForTests() {
2203 GPUProcessManager
* gpm
= GPUProcessManager::Get();
2205 // gfxPlatform has not been initialized.
2206 return NS_ERROR_NOT_INITIALIZED
;
2213 NS_IMETHODIMP
GfxInfoBase::CrashGPUProcessForTests() {
2214 GPUProcessManager
* gpm
= GPUProcessManager::Get();
2216 // gfxPlatform has not been initialized.
2217 return NS_ERROR_NOT_INITIALIZED
;
2220 gpm
->CrashProcess();
2224 GfxInfoCollectorBase::GfxInfoCollectorBase() {
2225 GfxInfoBase::AddCollector(this);
2228 GfxInfoCollectorBase::~GfxInfoCollectorBase() {
2229 GfxInfoBase::RemoveCollector(this);