1 /* -*- Mode: C++; tab-width: 8; 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/. */
12 #include <sys/utsname.h>
15 #include "nsCRTGlue.h"
16 #include "nsExceptionHandler.h"
17 #include "nsUnicharUtils.h"
19 #include "nsPrintfCString.h"
20 #include "nsWhitespaceTokenizer.h"
21 #include "mozilla/Telemetry.h"
22 #include "mozilla/gfx/Logging.h"
23 #include "mozilla/SSE.h"
25 #include "GfxInfoX11.h"
29 # include "mozilla/WidgetUtilsGtk.h"
30 # include "mozilla/widget/nsWaylandDisplay.h"
31 # include "mozilla/widget/DMABufLibWrapper.h"
34 #define EXIT_STATUS_BUFFER_TOO_SMALL 2
36 bool fire_glxtest_process();
39 namespace mozilla::widget
{
42 NS_IMPL_ISUPPORTS_INHERITED(GfxInfo
, GfxInfoBase
, nsIGfxInfoDebug
)
45 // these global variables will be set when firing the glxtest process
46 int glxtest_pipe
= -1;
47 pid_t glxtest_pid
= 0;
49 nsresult
GfxInfo::Init() {
52 mHasTextureFromPixmap
= false;
54 mIsAccelerated
= true;
57 mHasMultipleGPUs
= false;
58 mGlxTestError
= false;
59 return GfxInfoBase::Init();
62 void GfxInfo::AddCrashReportAnnotations() {
63 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID
,
65 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID
,
67 CrashReporter::AnnotateCrashReport(
68 CrashReporter::Annotation::AdapterDriverVendor
, mDriverVendor
);
69 CrashReporter::AnnotateCrashReport(
70 CrashReporter::Annotation::AdapterDriverVersion
, mDriverVersion
);
71 CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::IsWayland
,
73 CrashReporter::AnnotateCrashReport(
74 CrashReporter::Annotation::DesktopEnvironment
, mDesktopEnvironment
);
76 if (mHasMultipleGPUs
) {
78 note
.AppendLiteral("Has dual GPUs.");
79 if (!mSecondaryVendorId
.IsEmpty()) {
80 note
.AppendLiteral(" GPU #2: AdapterVendorID2: ");
81 note
.Append(mSecondaryVendorId
);
82 note
.AppendLiteral(", AdapterDeviceID2: ");
83 note
.Append(mSecondaryDeviceId
);
85 CrashReporter::AppendAppNotesToCrashReport(note
);
89 void GfxInfo::GetData() {
90 GfxInfoBase::GetData();
92 // to understand this function, see bug 639842. We retrieve the OpenGL driver
93 // information in a separate process to protect against bad drivers.
95 // if glxtest_pipe == -1, that means that we already read the information
96 if (glxtest_pipe
== -1) return;
98 enum { buf_size
= 2048 };
100 ssize_t bytesread
= read(glxtest_pipe
, &buf
,
101 buf_size
- 1); // -1 because we'll append a zero
105 // bytesread < 0 would mean that the above read() call failed.
106 // This should never happen. If it did, the outcome would be to blocklist
110 } else if (bytesread
== buf_size
- 1) {
111 gfxCriticalNote
<< "glxtest: read from pipe exceeded buffer size";
114 // let buf be a zero-terminated string
117 // Wait for the glxtest process to finish. This serves 2 purposes:
118 // * avoid having a zombie glxtest process laying around
119 // * get the glxtest process status info.
120 int glxtest_status
= 0;
121 bool wait_for_glxtest_process
= true;
122 bool waiting_for_glxtest_process_failed
= false;
123 int waitpid_errno
= 0;
124 while (wait_for_glxtest_process
) {
125 wait_for_glxtest_process
= false;
126 if (waitpid(glxtest_pid
, &glxtest_status
, 0) == -1) {
127 waitpid_errno
= errno
;
128 if (waitpid_errno
== EINTR
) {
129 wait_for_glxtest_process
= true;
132 // ECHILD happens when the glxtest process got reaped got reaped after a
133 // PR_CreateProcess as per bug 227246. This shouldn't matter, as we
134 // still seem to get the data from the pipe, and if we didn't, the
135 // outcome would be to blocklist anyway.
136 waiting_for_glxtest_process_failed
= (waitpid_errno
!= ECHILD
);
141 int exit_code
= EXIT_FAILURE
;
142 bool exited_with_error_code
= false;
143 if (!waiting_for_glxtest_process_failed
&& WIFEXITED(glxtest_status
)) {
144 exit_code
= WEXITSTATUS(glxtest_status
);
145 exited_with_error_code
= exit_code
!= EXIT_SUCCESS
;
148 bool received_signal
=
149 !waiting_for_glxtest_process_failed
&& WIFSIGNALED(glxtest_status
);
151 bool error
= waiting_for_glxtest_process_failed
|| exited_with_error_code
||
153 bool errorLog
= false;
156 nsCString glRenderer
;
158 nsCString textureFromPixmap
;
161 // Available if GLX_MESA_query_renderer is supported.
162 nsCString mesaVendor
;
163 nsCString mesaDevice
;
164 nsCString mesaAccelerated
;
165 // Available if using a DRI-based libGL stack.
167 nsCString screenInfo
;
168 nsCString adapterRam
;
170 nsCString drmRenderDevice
;
172 AutoTArray
<nsCString
, 2> pciVendors
;
173 AutoTArray
<nsCString
, 2> pciDevices
;
175 nsCString
* stringToFill
= nullptr;
176 bool logString
= false;
180 char* line
= NS_strtok("\n", &bufptr
);
183 stringToFill
->Assign(line
);
184 stringToFill
= nullptr;
185 } else if (logString
) {
186 gfxCriticalNote
<< "glxtest: " << line
;
188 } else if (!strcmp(line
, "VENDOR")) {
189 stringToFill
= &glVendor
;
190 } else if (!strcmp(line
, "RENDERER")) {
191 stringToFill
= &glRenderer
;
192 } else if (!strcmp(line
, "VERSION")) {
193 stringToFill
= &glVersion
;
194 } else if (!strcmp(line
, "TFP")) {
195 stringToFill
= &textureFromPixmap
;
196 } else if (!strcmp(line
, "MESA_VENDOR_ID")) {
197 stringToFill
= &mesaVendor
;
198 } else if (!strcmp(line
, "MESA_DEVICE_ID")) {
199 stringToFill
= &mesaDevice
;
200 } else if (!strcmp(line
, "MESA_ACCELERATED")) {
201 stringToFill
= &mesaAccelerated
;
202 } else if (!strcmp(line
, "MESA_VRAM")) {
203 stringToFill
= &adapterRam
;
204 } else if (!strcmp(line
, "DRI_DRIVER")) {
205 stringToFill
= &driDriver
;
206 } else if (!strcmp(line
, "SCREEN_INFO")) {
207 stringToFill
= &screenInfo
;
208 } else if (!strcmp(line
, "PCI_VENDOR_ID")) {
209 stringToFill
= pciVendors
.AppendElement();
210 } else if (!strcmp(line
, "PCI_DEVICE_ID")) {
211 stringToFill
= pciDevices
.AppendElement();
212 } else if (!strcmp(line
, "DRM_RENDERDEVICE")) {
213 stringToFill
= &drmRenderDevice
;
214 } else if (!strcmp(line
, "TEST_TYPE")) {
215 stringToFill
= &testType
;
216 } else if (!strcmp(line
, "WARNING")) {
218 } else if (!strcmp(line
, "ERROR")) {
224 MOZ_ASSERT(pciDevices
.Length() == pciVendors
.Length(),
225 "Missing PCI vendors/devices");
227 size_t pciLen
= std::min(pciVendors
.Length(), pciDevices
.Length());
228 mHasMultipleGPUs
= pciLen
> 1;
230 if (!strcmp(textureFromPixmap
.get(), "TRUE")) mHasTextureFromPixmap
= true;
232 // only useful for Linux kernel version check for FGLRX driver.
233 // assumes X client == X server, which is sad.
234 struct utsname unameobj
;
235 if (uname(&unameobj
) >= 0) {
236 mOS
.Assign(unameobj
.sysname
);
237 mOSRelease
.Assign(unameobj
.release
);
240 const char* spoofedVendor
= PR_GetEnv("MOZ_GFX_SPOOF_GL_VENDOR");
241 if (spoofedVendor
) glVendor
.Assign(spoofedVendor
);
242 const char* spoofedRenderer
= PR_GetEnv("MOZ_GFX_SPOOF_GL_RENDERER");
243 if (spoofedRenderer
) glRenderer
.Assign(spoofedRenderer
);
244 const char* spoofedVersion
= PR_GetEnv("MOZ_GFX_SPOOF_GL_VERSION");
245 if (spoofedVersion
) glVersion
.Assign(spoofedVersion
);
246 const char* spoofedOS
= PR_GetEnv("MOZ_GFX_SPOOF_OS");
247 if (spoofedOS
) mOS
.Assign(spoofedOS
);
248 const char* spoofedOSRelease
= PR_GetEnv("MOZ_GFX_SPOOF_OS_RELEASE");
249 if (spoofedOSRelease
) mOSRelease
.Assign(spoofedOSRelease
);
251 // Scan the GL_VERSION string for the GL and driver versions.
252 nsCWhitespaceTokenizer
tokenizer(glVersion
);
253 while (tokenizer
.hasMoreTokens()) {
254 nsCString
token(tokenizer
.nextToken());
255 unsigned int major
= 0, minor
= 0, revision
= 0, patch
= 0;
256 if (sscanf(token
.get(), "%u.%u.%u.%u", &major
, &minor
, &revision
, &patch
) >=
258 // A survey of GL_VENDOR strings indicates that the first version is
259 // always the GL version, the second is usually the driver version.
260 if (mGLMajorVersion
== 0) {
261 mGLMajorVersion
= major
;
262 mGLMinorVersion
= minor
;
263 } else if (mDriverVersion
.IsEmpty()) { // Not already spoofed.
265 nsPrintfCString("%u.%u.%u.%u", major
, minor
, revision
, patch
);
270 if (mGLMajorVersion
== 0) {
271 NS_WARNING("Failed to parse GL version!");
274 mDrmRenderDevice
= std::move(drmRenderDevice
);
275 mTestType
= std::move(testType
);
277 // Mesa always exposes itself in the GL_VERSION string, but not always the
279 mIsMesa
= glVersion
.Find("Mesa") != -1;
281 // We need to use custom driver vendor IDs for mesa so we can treat them
282 // differently than the proprietary drivers.
284 mIsAccelerated
= !mesaAccelerated
.Equals("FALSE");
285 // Process software rasterizers before the DRI driver string; we may be
286 // forcing software rasterization on a DRI-accelerated X server by using
287 // LIBGL_ALWAYS_SOFTWARE or a similar restriction.
288 if (strcasestr(glRenderer
.get(), "llvmpipe")) {
290 GfxDriverInfo::GetDriverVendor(DriverVendor::MesaLLVMPipe
),
292 mIsAccelerated
= false;
293 } else if (strcasestr(glRenderer
.get(), "softpipe")) {
295 GfxDriverInfo::GetDriverVendor(DriverVendor::MesaSoftPipe
),
297 mIsAccelerated
= false;
298 } else if (strcasestr(glRenderer
.get(), "software rasterizer") ||
300 // Fallback to reporting swrast if GLX_MESA_query_renderer tells us
301 // we're using an unaccelerated context.
302 CopyUTF16toUTF8(GfxDriverInfo::GetDriverVendor(DriverVendor::MesaSWRast
),
304 mIsAccelerated
= false;
305 } else if (!driDriver
.IsEmpty()) {
306 mDriverVendor
= nsPrintfCString("mesa/%s", driDriver
.get());
308 // Some other mesa configuration where we couldn't get enough info.
309 NS_WARNING("Failed to detect Mesa driver being used!");
310 CopyUTF16toUTF8(GfxDriverInfo::GetDriverVendor(DriverVendor::MesaUnknown
),
314 if (!mesaVendor
.IsEmpty()) {
315 mVendorId
= mesaVendor
;
318 if (!mesaDevice
.IsEmpty()) {
319 mDeviceId
= mesaDevice
;
321 } else if (glVendor
.EqualsLiteral("NVIDIA Corporation")) {
322 CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::NVIDIA
),
324 mDriverVendor
.AssignLiteral("nvidia/unknown");
325 // TODO: Use NV-CONTROL X11 extension to query Device ID and VRAM.
326 } else if (glVendor
.EqualsLiteral("ATI Technologies Inc.")) {
327 CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::ATI
),
329 mDriverVendor
.AssignLiteral("ati/unknown");
330 // TODO: Look into ways to find the device ID on FGLRX.
332 NS_WARNING("Failed to detect GL vendor!");
335 if (!screenInfo
.IsEmpty()) {
337 PRInt32 loc
= screenInfo
.Find(";", PR_FALSE
, start
);
338 while (loc
!= kNotFound
) {
340 nsCString
line(screenInfo
.get() + start
, loc
- start
);
342 if (sscanf(line
.get(), "%ux%u:%u", &info
.mWidth
, &info
.mHeight
,
344 info
.mIsDefault
= isDefault
!= 0;
345 mScreenInfo
.AppendElement(info
);
349 loc
= screenInfo
.Find(";", PR_FALSE
, start
);
353 if (!adapterRam
.IsEmpty()) {
354 mAdapterRAM
= (uint32_t)atoi(adapterRam
.get());
357 // If we have the DRI driver, we can derive the vendor ID from that if needed.
358 if (mVendorId
.IsEmpty() && !driDriver
.IsEmpty()) {
359 const char* nvidiaDrivers
[] = {"nouveau", "tegra", nullptr};
360 for (size_t i
= 0; nvidiaDrivers
[i
]; ++i
) {
361 if (driDriver
.Equals(nvidiaDrivers
[i
])) {
362 CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::NVIDIA
),
368 if (mVendorId
.IsEmpty()) {
369 const char* intelDrivers
[] = {"iris", "i915", "i965",
370 "i810", "intel", nullptr};
371 for (size_t i
= 0; intelDrivers
[i
]; ++i
) {
372 if (driDriver
.Equals(intelDrivers
[i
])) {
373 CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::Intel
),
380 if (mVendorId
.IsEmpty()) {
381 const char* amdDrivers
[] = {"r600", "r200", "r100",
382 "radeon", "radeonsi", nullptr};
383 for (size_t i
= 0; amdDrivers
[i
]; ++i
) {
384 if (driDriver
.Equals(amdDrivers
[i
])) {
385 CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::ATI
),
392 if (mVendorId
.IsEmpty()) {
393 if (driDriver
.EqualsLiteral("freedreno")) {
394 CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::Qualcomm
),
400 // If we still don't have a vendor ID, we can try the PCI vendor list.
401 if (mVendorId
.IsEmpty()) {
402 if (pciVendors
.Length() == 1) {
403 mVendorId
= pciVendors
[0];
404 } else if (pciVendors
.IsEmpty()) {
405 gfxCriticalNote
<< "No GPUs detected via PCI";
408 << "More than 1 GPU detected via PCI, cannot deduce vendor";
412 // If we know the vendor ID, but didn't get a device ID, we can guess from the
414 if (mDeviceId
.IsEmpty() && !mVendorId
.IsEmpty()) {
415 for (size_t i
= 0; i
< pciLen
; ++i
) {
416 if (mVendorId
.Equals(pciVendors
[i
])) {
417 if (mDeviceId
.IsEmpty()) {
418 mDeviceId
= pciDevices
[i
];
420 gfxCriticalNote
<< "More than 1 GPU from same vendor detected via "
421 "PCI, cannot deduce device";
422 mDeviceId
.Truncate();
429 // Assuming we know the vendor, we should check for a secondary card.
430 if (!mVendorId
.IsEmpty()) {
433 << "More than 2 GPUs detected via PCI, secondary GPU is arbitrary";
435 for (size_t i
= 0; i
< pciLen
; ++i
) {
436 if (!mVendorId
.Equals(pciVendors
[i
]) ||
437 (!mDeviceId
.IsEmpty() && !mDeviceId
.Equals(pciDevices
[i
]))) {
438 mSecondaryVendorId
= pciVendors
[i
];
439 mSecondaryDeviceId
= pciDevices
[i
];
445 // If we couldn't choose, log them.
446 if (mVendorId
.IsEmpty()) {
447 for (size_t i
= 0; i
< pciLen
; ++i
) {
448 gfxCriticalNote
<< "PCI candidate " << pciVendors
[i
].get() << "/"
449 << pciDevices
[i
].get();
453 // Fallback to GL_VENDOR and GL_RENDERER.
454 if (mVendorId
.IsEmpty()) {
455 mVendorId
.Assign(glVendor
.get());
457 if (mDeviceId
.IsEmpty()) {
458 mDeviceId
.Assign(glRenderer
.get());
461 mAdapterDescription
.Assign(glRenderer
);
463 mIsWayland
= GdkIsWaylandDisplay();
466 // Make a best effort guess at whether or not we are using the XWayland compat
467 // layer. For all intents and purposes, we should otherwise believe we are
469 const char* waylandDisplay
= getenv("WAYLAND_DISPLAY");
470 mIsXWayland
= !mIsWayland
&& waylandDisplay
;
472 // Make a best effort guess at the desktop environment in use. Sadly there
473 // does not appear to be a standard way to do this, so we check a few
474 // different environment variables and search for relevant keywords.
476 // Note that some users manually change these values. Some applications check
477 // the environment variable like we are here, and either not work or restrict
478 // functionality. There may be some heroics we could go through to determine
479 // the truth, but for the moment, this is the best we can do. This is
480 // something to keep in mind when updating the blocklist.
481 const char* desktopEnv
= getenv("XDG_CURRENT_DESKTOP");
483 desktopEnv
= getenv("DESKTOP_SESSION");
487 std::string
currentDesktop(desktopEnv
);
488 for (auto& c
: currentDesktop
) {
492 if (currentDesktop
.find("budgie") != std::string::npos
) {
493 // We need to check for Budgie first, because it might incorporate GNOME
494 // into the environment variable value.
496 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Budgie
),
497 mDesktopEnvironment
);
498 } else if (currentDesktop
.find("gnome") != std::string::npos
) {
500 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::GNOME
),
501 mDesktopEnvironment
);
502 } else if (currentDesktop
.find("kde") != std::string::npos
) {
504 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::KDE
),
505 mDesktopEnvironment
);
506 } else if (currentDesktop
.find("xfce") != std::string::npos
) {
508 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::XFCE
),
509 mDesktopEnvironment
);
510 } else if (currentDesktop
.find("cinnamon") != std::string::npos
) {
512 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Cinnamon
),
513 mDesktopEnvironment
);
514 } else if (currentDesktop
.find("enlightenment") != std::string::npos
) {
515 CopyUTF16toUTF8(GfxDriverInfo::GetDesktopEnvironment(
516 DesktopEnvironment::Enlightenment
),
517 mDesktopEnvironment
);
518 } else if (currentDesktop
.find("lxde") != std::string::npos
||
519 currentDesktop
.find("lubuntu") != std::string::npos
) {
521 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::LXDE
),
522 mDesktopEnvironment
);
523 } else if (currentDesktop
.find("openbox") != std::string::npos
) {
525 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Openbox
),
526 mDesktopEnvironment
);
527 } else if (currentDesktop
.find("i3") != std::string::npos
) {
529 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::i3
),
530 mDesktopEnvironment
);
531 } else if (currentDesktop
.find("mate") != std::string::npos
) {
533 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Mate
),
534 mDesktopEnvironment
);
535 } else if (currentDesktop
.find("unity") != std::string::npos
) {
537 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Unity
),
538 mDesktopEnvironment
);
539 } else if (currentDesktop
.find("pantheon") != std::string::npos
) {
541 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Pantheon
),
542 mDesktopEnvironment
);
543 } else if (currentDesktop
.find("lxqt") != std::string::npos
) {
545 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::LXQT
),
546 mDesktopEnvironment
);
547 } else if (currentDesktop
.find("deepin") != std::string::npos
) {
549 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Deepin
),
550 mDesktopEnvironment
);
551 } else if (currentDesktop
.find("dwm") != std::string::npos
) {
553 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Dwm
),
554 mDesktopEnvironment
);
558 if (mDesktopEnvironment
.IsEmpty()) {
559 if (getenv("GNOME_DESKTOP_SESSION_ID")) {
561 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::GNOME
),
562 mDesktopEnvironment
);
563 } else if (getenv("KDE_FULL_SESSION")) {
565 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::KDE
),
566 mDesktopEnvironment
);
567 } else if (getenv("MATE_DESKTOP_SESSION_ID")) {
569 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Mate
),
570 mDesktopEnvironment
);
571 } else if (getenv("LXQT_SESSION_CONFIG")) {
573 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::LXQT
),
574 mDesktopEnvironment
);
577 GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Unknown
),
578 mDesktopEnvironment
);
582 if (error
|| errorLog
|| mTestType
.IsEmpty()) {
583 if (!mAdapterDescription
.IsEmpty()) {
584 mAdapterDescription
.AppendLiteral(" (See failure log)");
586 mAdapterDescription
.AppendLiteral("See failure log");
589 mGlxTestError
= true;
593 nsAutoCString
msg("glxtest: process failed");
594 if (waiting_for_glxtest_process_failed
) {
595 msg
.AppendPrintf(" (waitpid failed with errno=%d for pid %d)",
596 waitpid_errno
, glxtest_pid
);
599 if (exited_with_error_code
) {
600 if (exit_code
== EXIT_STATUS_BUFFER_TOO_SMALL
) {
601 msg
.AppendLiteral(" (buffer too small)");
603 msg
.AppendPrintf(" (exited with status %d)",
604 WEXITSTATUS(glxtest_status
));
607 if (received_signal
) {
608 msg
.AppendPrintf(" (received signal %d)", WTERMSIG(glxtest_status
));
611 gfxCriticalNote
<< msg
.get();
614 AddCrashReportAnnotations();
617 const nsTArray
<GfxDriverInfo
>& GfxInfo::GetGfxDriverInfo() {
618 if (!sDriverInfo
->Length()) {
619 // Mesa 10.0 provides the GLX_MESA_query_renderer extension, which allows us
620 // to query device IDs backing a GL context for blocklisting.
621 APPEND_TO_DRIVER_BLOCKLIST_EXT(
622 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
623 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::MesaAll
,
624 DeviceFamily::All
, GfxDriverInfo::allFeatures
,
625 nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
, DRIVER_LESS_THAN
,
626 V(10, 0, 0, 0), "FEATURE_FAILURE_OLD_MESA", "Mesa 10.0");
628 // NVIDIA baseline (ported from old blocklist)
629 APPEND_TO_DRIVER_BLOCKLIST_EXT(
630 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
631 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::NonMesaAll
,
632 DeviceFamily::NvidiaAll
, GfxDriverInfo::allFeatures
,
633 nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
, DRIVER_LESS_THAN
,
634 V(257, 21, 0, 0), "FEATURE_FAILURE_OLD_NVIDIA", "NVIDIA 257.21");
636 // fglrx baseline (chosen arbitrarily as 2013-07-22 release).
637 APPEND_TO_DRIVER_BLOCKLIST(
638 OperatingSystem::Linux
, DeviceFamily::AtiAll
,
639 GfxDriverInfo::allFeatures
, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
,
640 DRIVER_LESS_THAN
, V(13, 15, 100, 1), "FEATURE_FAILURE_OLD_FGLRX",
641 "fglrx 13.15.100.1");
643 ////////////////////////////////////
646 // Intel Mesa baseline, chosen arbitrarily.
647 APPEND_TO_DRIVER_BLOCKLIST(
648 OperatingSystem::Linux
, DeviceFamily::IntelAll
,
649 nsIGfxInfo::FEATURE_WEBRENDER
,
650 nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
, DRIVER_LESS_THAN
,
651 V(17, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 17.0.0.0");
653 // Nvidia Mesa baseline, see bug 1563859.
654 APPEND_TO_DRIVER_BLOCKLIST_EXT(
655 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
656 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::MesaAll
,
657 DeviceFamily::NvidiaAll
, nsIGfxInfo::FEATURE_WEBRENDER
,
658 nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
, DRIVER_LESS_THAN
,
659 V(18, 2, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 18.2.0.0");
661 #ifndef EARLY_BETA_OR_EARLIER
662 // Disable on all Nvidia devices not using Mesa for now.
663 APPEND_TO_DRIVER_BLOCKLIST_EXT(
664 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
665 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::NonMesaAll
,
666 DeviceFamily::NvidiaAll
, nsIGfxInfo::FEATURE_WEBRENDER
,
667 nsIGfxInfo::FEATURE_BLOCKED_DEVICE
, DRIVER_COMPARISON_IGNORED
,
668 V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_NO_LINUX_NVIDIA", "");
670 // Disable on all older Nvidia drivers due to stability issues.
671 APPEND_TO_DRIVER_BLOCKLIST_EXT(
672 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
673 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::NonMesaAll
,
674 DeviceFamily::NvidiaAll
, nsIGfxInfo::FEATURE_WEBRENDER
,
675 nsIGfxInfo::FEATURE_BLOCKED_DEVICE
, DRIVER_LESS_THAN
, V(460, 32, 3, 0),
676 "FEATURE_FAILURE_WEBRENDER_OLD_NVIDIA", "460.32.03");
679 // ATI Mesa baseline, chosen arbitrarily.
680 APPEND_TO_DRIVER_BLOCKLIST_EXT(
681 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
682 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::MesaAll
,
683 DeviceFamily::AtiAll
, nsIGfxInfo::FEATURE_WEBRENDER
,
684 nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
, DRIVER_LESS_THAN
,
685 V(17, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 17.0.0.0");
687 // Bug 1690568 / Bug 1393793 - Require Mesa 17.3.0+ for devices using the
688 // r600 driver to avoid shader compilation issues.
689 APPEND_TO_DRIVER_BLOCKLIST_EXT(
690 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
691 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::MesaR600
,
692 DeviceFamily::All
, nsIGfxInfo::FEATURE_WEBRENDER
,
693 nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION
, DRIVER_LESS_THAN
,
694 V(17, 3, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA_R600",
697 // Disable on all ATI devices not using Mesa for now.
698 APPEND_TO_DRIVER_BLOCKLIST_EXT(
699 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
700 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::NonMesaAll
,
701 DeviceFamily::AtiAll
, nsIGfxInfo::FEATURE_WEBRENDER
,
702 nsIGfxInfo::FEATURE_BLOCKED_DEVICE
, DRIVER_COMPARISON_IGNORED
,
703 V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_NO_LINUX_ATI", "");
705 // Bug 1673939 - Garbled text on RS880 GPUs with Mesa drivers.
706 APPEND_TO_DRIVER_BLOCKLIST_EXT(
707 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
708 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::MesaAll
,
709 DeviceFamily::AmdR600
, nsIGfxInfo::FEATURE_WEBRENDER
,
710 nsIGfxInfo::FEATURE_BLOCKED_DEVICE
, DRIVER_COMPARISON_IGNORED
,
711 V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_BUG_1673939",
712 "https://gitlab.freedesktop.org/mesa/mesa/-/issues/3720");
714 #ifndef EARLY_BETA_OR_EARLIER
715 // Bug 1635186 - Poor performance with video playing in a background window
717 APPEND_TO_DRIVER_BLOCKLIST_EXT(
718 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
719 DesktopEnvironment::All
, WindowProtocol::XWayland
, DriverVendor::All
,
720 DeviceFamily::All
, nsIGfxInfo::FEATURE_WEBRENDER
,
721 nsIGfxInfo::FEATURE_BLOCKED_DEVICE
, DRIVER_COMPARISON_IGNORED
,
722 V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_BUG_1635186",
723 "https://bugzilla.mozilla.org/show_bug.cgi?id=1635186");
726 ////////////////////////////////////
727 // FEATURE_WEBRENDER - ALLOWLIST
729 // Intel Mesa baseline, chosen arbitrarily.
730 APPEND_TO_DRIVER_BLOCKLIST_EXT(
731 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
732 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::MesaAll
,
733 DeviceFamily::IntelRolloutWebRender
, nsIGfxInfo::FEATURE_WEBRENDER
,
734 nsIGfxInfo::FEATURE_ALLOW_ALWAYS
, DRIVER_GREATER_THAN_OR_EQUAL
,
735 V(17, 0, 0, 0), "FEATURE_ROLLOUT_INTEL_MESA",
738 // Nvidia Mesa baseline, see bug 1563859.
739 APPEND_TO_DRIVER_BLOCKLIST_EXT(
740 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
741 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::MesaAll
,
742 DeviceFamily::NvidiaRolloutWebRender
, nsIGfxInfo::FEATURE_WEBRENDER
,
743 nsIGfxInfo::FEATURE_ALLOW_QUALIFIED
, DRIVER_GREATER_THAN_OR_EQUAL
,
744 V(18, 2, 0, 0), "FEATURE_ROLLOUT_NVIDIA_MESA",
747 // Nvidia proprietary driver baseline, see bug 1673752.
748 APPEND_TO_DRIVER_BLOCKLIST_EXT(
749 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
750 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::NonMesaAll
,
751 DeviceFamily::NvidiaAll
, nsIGfxInfo::FEATURE_WEBRENDER
,
752 nsIGfxInfo::FEATURE_ALLOW_QUALIFIED
, DRIVER_GREATER_THAN_OR_EQUAL
,
753 V(460, 32, 3, 0), "FEATURE_ROLLOUT_NVIDIA_BINARY", "460.32.03");
755 // ATI Mesa baseline, chosen arbitrarily.
756 APPEND_TO_DRIVER_BLOCKLIST_EXT(
757 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
758 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::MesaAll
,
759 DeviceFamily::AtiRolloutWebRender
, nsIGfxInfo::FEATURE_WEBRENDER
,
760 nsIGfxInfo::FEATURE_ALLOW_ALWAYS
, DRIVER_GREATER_THAN_OR_EQUAL
,
761 V(17, 0, 0, 0), "FEATURE_ROLLOUT_ATI_MESA", "Mesa 17.0.0.0");
763 ////////////////////////////////////
764 // FEATURE_WEBRENDER_SOFTWARE - ALLOWLIST
765 #ifdef EARLY_BETA_OR_EARLIER
766 APPEND_TO_DRIVER_BLOCKLIST(OperatingSystem::Linux
, DeviceFamily::All
,
767 nsIGfxInfo::FEATURE_WEBRENDER_SOFTWARE
,
768 nsIGfxInfo::FEATURE_ALLOW_ALWAYS
,
769 DRIVER_COMPARISON_IGNORED
, V(0, 0, 0, 0),
770 "FEATURE_ROLLOUT_EARLY_BETA_SOFTWARE_WR", "");
773 APPEND_TO_DRIVER_BLOCKLIST_EXT(
774 OperatingSystem::Linux
, ScreenSizeStatus::SmallAndMedium
,
775 BatteryStatus::All
, DesktopEnvironment::All
, WindowProtocol::All
,
776 DriverVendor::All
, DeviceFamily::All
,
777 nsIGfxInfo::FEATURE_WEBRENDER_SOFTWARE
,
778 nsIGfxInfo::FEATURE_ALLOW_ALWAYS
, DRIVER_COMPARISON_IGNORED
,
779 V(0, 0, 0, 0), "FEATURE_ROLLOUT_S_M_SCRN_SOFTWARE_WR", "");
781 ////////////////////////////////////
783 APPEND_TO_DRIVER_BLOCKLIST(
784 OperatingSystem::Linux
, DeviceFamily::All
, nsIGfxInfo::FEATURE_X11_EGL
,
785 nsIGfxInfo::FEATURE_BLOCKED_DEVICE
, DRIVER_COMPARISON_IGNORED
,
786 V(0, 0, 0, 0), "FEATURE_FAILURE_X11_EGL_DISABLED", "");
788 ////////////////////////////////////
790 APPEND_TO_DRIVER_BLOCKLIST_EXT(
791 OperatingSystem::Linux
, ScreenSizeStatus::All
, BatteryStatus::All
,
792 DesktopEnvironment::All
, WindowProtocol::All
, DriverVendor::MesaNouveau
,
793 DeviceFamily::All
, nsIGfxInfo::FEATURE_THREADSAFE_GL
,
794 nsIGfxInfo::FEATURE_BLOCKED_DEVICE
, DRIVER_COMPARISON_IGNORED
,
795 V(0, 0, 0, 0), "FEATURE_FAILURE_THREADSAFE_GL", "");
800 bool GfxInfo::DoesWindowProtocolMatch(const nsAString
& aBlocklistWindowProtocol
,
801 const nsAString
& aWindowProtocol
) {
803 aBlocklistWindowProtocol
.Equals(
804 GfxDriverInfo::GetWindowProtocol(WindowProtocol::WaylandAll
),
805 nsCaseInsensitiveStringComparator
)) {
809 aBlocklistWindowProtocol
.Equals(
810 GfxDriverInfo::GetWindowProtocol(WindowProtocol::X11All
),
811 nsCaseInsensitiveStringComparator
)) {
814 return GfxInfoBase::DoesWindowProtocolMatch(aBlocklistWindowProtocol
,
818 bool GfxInfo::DoesDriverVendorMatch(const nsAString
& aBlocklistVendor
,
819 const nsAString
& aDriverVendor
) {
821 if (aBlocklistVendor
.Equals(
822 GfxDriverInfo::GetDriverVendor(DriverVendor::MesaAll
),
823 nsCaseInsensitiveStringComparator
)) {
826 if (mIsAccelerated
&&
827 aBlocklistVendor
.Equals(
828 GfxDriverInfo::GetDriverVendor(DriverVendor::HardwareMesaAll
),
829 nsCaseInsensitiveStringComparator
)) {
832 if (!mIsAccelerated
&&
833 aBlocklistVendor
.Equals(
834 GfxDriverInfo::GetDriverVendor(DriverVendor::SoftwareMesaAll
),
835 nsCaseInsensitiveStringComparator
)) {
839 if (!mIsMesa
&& aBlocklistVendor
.Equals(
840 GfxDriverInfo::GetDriverVendor(DriverVendor::NonMesaAll
),
841 nsCaseInsensitiveStringComparator
)) {
844 return GfxInfoBase::DoesDriverVendorMatch(aBlocklistVendor
, aDriverVendor
);
847 nsresult
GfxInfo::GetFeatureStatusImpl(
848 int32_t aFeature
, int32_t* aStatus
, nsAString
& aSuggestedDriverVersion
,
849 const nsTArray
<GfxDriverInfo
>& aDriverInfo
, nsACString
& aFailureId
,
850 OperatingSystem
* aOS
/* = nullptr */)
853 NS_ENSURE_ARG_POINTER(aStatus
);
854 *aStatus
= nsIGfxInfo::FEATURE_STATUS_UNKNOWN
;
855 aSuggestedDriverVersion
.SetIsVoid(true);
856 OperatingSystem os
= OperatingSystem::Linux
;
859 if (sShutdownOccurred
) {
866 // If glxtest failed, block all features by default.
867 *aStatus
= nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
868 aFailureId
= "FEATURE_FAILURE_GLXTEST_FAILED";
872 if (mGLMajorVersion
== 1) {
873 // We're on OpenGL 1. In most cases that indicates really old hardware.
874 // We better block them, rather than rely on them to fail gracefully,
875 // because they don't! see bug 696636
876 *aStatus
= nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
877 aFailureId
= "FEATURE_FAILURE_OPENGL_1";
881 // Blocklist software GL implementations from using layers acceleration.
882 // On the test infrastructure, we'll force-enable layers acceleration.
883 if (aFeature
== nsIGfxInfo::FEATURE_OPENGL_LAYERS
&& !mIsAccelerated
&&
884 !PR_GetEnv("MOZ_LAYERS_ALLOW_SOFTWARE_GL")) {
885 *aStatus
= nsIGfxInfo::FEATURE_BLOCKED_DEVICE
;
886 aFailureId
= "FEATURE_FAILURE_SOFTWARE_GL";
890 return GfxInfoBase::GetFeatureStatusImpl(
891 aFeature
, aStatus
, aSuggestedDriverVersion
, aDriverInfo
, aFailureId
, &os
);
895 GfxInfo::GetD2DEnabled(bool* aEnabled
) { return NS_ERROR_FAILURE
; }
898 GfxInfo::GetDWriteEnabled(bool* aEnabled
) { return NS_ERROR_FAILURE
; }
901 GfxInfo::GetDWriteVersion(nsAString
& aDwriteVersion
) {
902 return NS_ERROR_FAILURE
;
905 NS_IMETHODIMP
GfxInfo::GetHasBattery(bool* aHasBattery
) {
906 return NS_ERROR_NOT_IMPLEMENTED
;
910 GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality
) {
911 return NS_ERROR_FAILURE
;
915 GfxInfo::GetCleartypeParameters(nsAString
& aCleartypeParams
) {
916 return NS_ERROR_FAILURE
;
920 GfxInfo::GetWindowProtocol(nsAString
& aWindowProtocol
) {
923 aWindowProtocol
= GfxDriverInfo::GetWindowProtocol(WindowProtocol::Wayland
);
924 } else if (mIsXWayland
) {
926 GfxDriverInfo::GetWindowProtocol(WindowProtocol::XWayland
);
928 aWindowProtocol
= GfxDriverInfo::GetWindowProtocol(WindowProtocol::X11
);
930 Telemetry::ScalarSet(Telemetry::ScalarID::GFX_LINUX_WINDOW_PROTOCOL
,
936 GfxInfo::GetDesktopEnvironment(nsAString
& aDesktopEnvironment
) {
938 AppendASCIItoUTF16(mDesktopEnvironment
, aDesktopEnvironment
);
943 GfxInfo::GetTestType(nsAString
& aTestType
) {
945 AppendASCIItoUTF16(mTestType
, aTestType
);
950 GfxInfo::GetAdapterDescription(nsAString
& aAdapterDescription
) {
952 AppendASCIItoUTF16(mAdapterDescription
, aAdapterDescription
);
957 GfxInfo::GetAdapterDescription2(nsAString
& aAdapterDescription
) {
958 return NS_ERROR_FAILURE
;
962 GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM
) {
964 *aAdapterRAM
= mAdapterRAM
;
969 GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM
) { return NS_ERROR_FAILURE
; }
972 GfxInfo::GetAdapterDriver(nsAString
& aAdapterDriver
) {
973 aAdapterDriver
.Truncate();
978 GfxInfo::GetAdapterDriver2(nsAString
& aAdapterDriver
) {
979 return NS_ERROR_FAILURE
;
983 GfxInfo::GetAdapterDriverVendor(nsAString
& aAdapterDriverVendor
) {
985 CopyASCIItoUTF16(mDriverVendor
, aAdapterDriverVendor
);
990 GfxInfo::GetAdapterDriverVendor2(nsAString
& aAdapterDriverVendor
) {
991 return NS_ERROR_FAILURE
;
995 GfxInfo::GetAdapterDriverVersion(nsAString
& aAdapterDriverVersion
) {
997 CopyASCIItoUTF16(mDriverVersion
, aAdapterDriverVersion
);
1002 GfxInfo::GetAdapterDriverVersion2(nsAString
& aAdapterDriverVersion
) {
1003 return NS_ERROR_FAILURE
;
1007 GfxInfo::GetAdapterDriverDate(nsAString
& aAdapterDriverDate
) {
1008 aAdapterDriverDate
.Truncate();
1013 GfxInfo::GetAdapterDriverDate2(nsAString
& aAdapterDriverDate
) {
1014 return NS_ERROR_FAILURE
;
1018 GfxInfo::GetAdapterVendorID(nsAString
& aAdapterVendorID
) {
1020 CopyUTF8toUTF16(mVendorId
, aAdapterVendorID
);
1025 GfxInfo::GetAdapterVendorID2(nsAString
& aAdapterVendorID
) {
1027 CopyUTF8toUTF16(mSecondaryVendorId
, aAdapterVendorID
);
1032 GfxInfo::GetAdapterDeviceID(nsAString
& aAdapterDeviceID
) {
1034 CopyUTF8toUTF16(mDeviceId
, aAdapterDeviceID
);
1039 GfxInfo::GetAdapterDeviceID2(nsAString
& aAdapterDeviceID
) {
1041 CopyUTF8toUTF16(mSecondaryDeviceId
, aAdapterDeviceID
);
1046 GfxInfo::GetAdapterSubsysID(nsAString
& aAdapterSubsysID
) {
1047 return NS_ERROR_FAILURE
;
1051 GfxInfo::GetAdapterSubsysID2(nsAString
& aAdapterSubsysID
) {
1052 return NS_ERROR_FAILURE
;
1056 GfxInfo::GetDisplayInfo(nsTArray
<nsString
>& aDisplayInfo
) {
1059 for (auto screenInfo
: mScreenInfo
) {
1060 nsString infoString
;
1061 infoString
.AppendPrintf("%dx%d %s", screenInfo
.mWidth
, screenInfo
.mHeight
,
1062 screenInfo
.mIsDefault
? "default" : "");
1063 aDisplayInfo
.AppendElement(infoString
);
1066 return aDisplayInfo
.IsEmpty() ? NS_ERROR_FAILURE
: NS_OK
;
1070 GfxInfo::GetDisplayWidth(nsTArray
<uint32_t>& aDisplayWidth
) {
1071 for (auto screenInfo
: mScreenInfo
) {
1072 aDisplayWidth
.AppendElement((uint32_t)screenInfo
.mWidth
);
1078 GfxInfo::GetDisplayHeight(nsTArray
<uint32_t>& aDisplayHeight
) {
1079 for (auto screenInfo
: mScreenInfo
) {
1080 aDisplayHeight
.AppendElement((uint32_t)screenInfo
.mHeight
);
1086 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active
) {
1087 // This is never the case, as the active GPU should be the primary GPU.
1088 *aIsGPU2Active
= false;
1093 GfxInfo::GetDrmRenderDevice(nsACString
& aDrmRenderDevice
) {
1095 aDrmRenderDevice
.Assign(mDrmRenderDevice
);
1101 // Implement nsIGfxInfoDebug
1102 // We don't support spoofing anything on Linux
1104 NS_IMETHODIMP
GfxInfo::SpoofVendorID(const nsAString
& aVendorID
) {
1106 CopyUTF16toUTF8(aVendorID
, mVendorId
);
1107 mIsAccelerated
= true;
1111 NS_IMETHODIMP
GfxInfo::SpoofDeviceID(const nsAString
& aDeviceID
) {
1113 CopyUTF16toUTF8(aDeviceID
, mDeviceId
);
1117 NS_IMETHODIMP
GfxInfo::SpoofDriverVersion(const nsAString
& aDriverVersion
) {
1119 CopyUTF16toUTF8(aDriverVersion
, mDriverVersion
);
1123 NS_IMETHODIMP
GfxInfo::SpoofOSVersion(uint32_t aVersion
) {
1124 // We don't support OS versioning on Linux. There's just "Linux".
1128 NS_IMETHODIMP
GfxInfo::FireTestProcess() {
1129 // If the pid is zero, then we have never run the test process to query for
1130 // driver information. This would normally be run on startup, but we need to
1131 // manually invoke it for XPC shell tests.
1132 if (glxtest_pid
== 0) {
1133 fire_glxtest_process();
1140 } // namespace mozilla::widget