1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: sw=2 ts=8 et :
3  */
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/. */
7 
8 #include "GfxInfo.h"
9 
10 #include <cctype>
11 #include <errno.h>
12 #include <unistd.h>
13 #include <string>
14 #include <sys/types.h>
15 #include <sys/utsname.h>
16 #include <sys/wait.h>
17 
18 #include "mozilla/gfx/Logging.h"
19 #include "mozilla/SSE.h"
20 #include "mozilla/Telemetry.h"
21 #include "nsCRTGlue.h"
22 #include "nsExceptionHandler.h"
23 #include "nsPrintfCString.h"
24 #include "nsUnicharUtils.h"
25 #include "nsWhitespaceTokenizer.h"
26 #include "prenv.h"
27 #include "WidgetUtilsGtk.h"
28 
29 #define EXIT_STATUS_BUFFER_TOO_SMALL 2
30 #ifdef DEBUG
31 bool fire_glxtest_process();
32 #endif
33 
34 namespace mozilla::widget {
35 
36 #ifdef DEBUG
37 NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
38 #endif
39 
40 // these global variables will be set when firing the glxtest process
41 int glxtest_pipe = -1;
42 pid_t glxtest_pid = 0;
43 
Init()44 nsresult GfxInfo::Init() {
45   mGLMajorVersion = 0;
46   mGLMinorVersion = 0;
47   mHasTextureFromPixmap = false;
48   mIsMesa = false;
49   mIsAccelerated = true;
50   mIsWayland = false;
51   mIsXWayland = false;
52   mHasMultipleGPUs = false;
53   mGlxTestError = false;
54   return GfxInfoBase::Init();
55 }
56 
AddCrashReportAnnotations()57 void GfxInfo::AddCrashReportAnnotations() {
58   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
59                                      mVendorId);
60   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
61                                      mDeviceId);
62   CrashReporter::AnnotateCrashReport(
63       CrashReporter::Annotation::AdapterDriverVendor, mDriverVendor);
64   CrashReporter::AnnotateCrashReport(
65       CrashReporter::Annotation::AdapterDriverVersion, mDriverVersion);
66   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::IsWayland,
67                                      mIsWayland);
68   CrashReporter::AnnotateCrashReport(
69       CrashReporter::Annotation::DesktopEnvironment, mDesktopEnvironment);
70 
71   if (mHasMultipleGPUs) {
72     nsAutoCString note;
73     note.AppendLiteral("Has dual GPUs.");
74     if (!mSecondaryVendorId.IsEmpty()) {
75       note.AppendLiteral(" GPU #2: AdapterVendorID2: ");
76       note.Append(mSecondaryVendorId);
77       note.AppendLiteral(", AdapterDeviceID2: ");
78       note.Append(mSecondaryDeviceId);
79     }
80     CrashReporter::AppendAppNotesToCrashReport(note);
81   }
82 }
83 
GetData()84 void GfxInfo::GetData() {
85   GfxInfoBase::GetData();
86 
87   // to understand this function, see bug 639842. We retrieve the OpenGL driver
88   // information in a separate process to protect against bad drivers.
89 
90   // if glxtest_pipe == -1, that means that we already read the information
91   if (glxtest_pipe == -1) return;
92 
93   enum { buf_size = 2048 };
94   char buf[buf_size];
95   ssize_t bytesread = read(glxtest_pipe, &buf,
96                            buf_size - 1);  // -1 because we'll append a zero
97   close(glxtest_pipe);
98   glxtest_pipe = -1;
99 
100   // bytesread < 0 would mean that the above read() call failed.
101   // This should never happen. If it did, the outcome would be to blocklist
102   // anyway.
103   if (bytesread < 0) {
104     bytesread = 0;
105   } else if (bytesread == buf_size - 1) {
106     gfxCriticalNote << "glxtest: read from pipe exceeded buffer size";
107   }
108 
109   // let buf be a zero-terminated string
110   buf[bytesread] = 0;
111 
112   // Wait for the glxtest process to finish. This serves 2 purposes:
113   // * avoid having a zombie glxtest process laying around
114   // * get the glxtest process status info.
115   int glxtest_status = 0;
116   bool wait_for_glxtest_process = true;
117   bool waiting_for_glxtest_process_failed = false;
118   int waitpid_errno = 0;
119   while (wait_for_glxtest_process) {
120     wait_for_glxtest_process = false;
121     if (waitpid(glxtest_pid, &glxtest_status, 0) == -1) {
122       waitpid_errno = errno;
123       if (waitpid_errno == EINTR) {
124         wait_for_glxtest_process = true;
125       } else {
126         // Bug 718629
127         // ECHILD happens when the glxtest process got reaped got reaped after a
128         // PR_CreateProcess as per bug 227246. This shouldn't matter, as we
129         // still seem to get the data from the pipe, and if we didn't, the
130         // outcome would be to blocklist anyway.
131         waiting_for_glxtest_process_failed = (waitpid_errno != ECHILD);
132       }
133     }
134   }
135 
136   int exit_code = EXIT_FAILURE;
137   bool exited_with_error_code = false;
138   if (!waiting_for_glxtest_process_failed && WIFEXITED(glxtest_status)) {
139     exit_code = WEXITSTATUS(glxtest_status);
140     exited_with_error_code = exit_code != EXIT_SUCCESS;
141   }
142 
143   bool received_signal =
144       !waiting_for_glxtest_process_failed && WIFSIGNALED(glxtest_status);
145 
146   bool error = waiting_for_glxtest_process_failed || exited_with_error_code ||
147                received_signal;
148   bool errorLog = false;
149 
150   nsCString glVendor;
151   nsCString glRenderer;
152   nsCString glVersion;
153   nsCString textureFromPixmap;
154   nsCString testType;
155 
156   // Available if GLX_MESA_query_renderer is supported.
157   nsCString mesaVendor;
158   nsCString mesaDevice;
159   nsCString mesaAccelerated;
160   // Available if using a DRI-based libGL stack.
161   nsCString driDriver;
162   nsCString screenInfo;
163   nsCString adapterRam;
164 
165   nsCString drmRenderDevice;
166 
167   nsCString ddxDriver;
168 
169   AutoTArray<nsCString, 2> pciVendors;
170   AutoTArray<nsCString, 2> pciDevices;
171 
172   nsCString* stringToFill = nullptr;
173   bool logString = false;
174 
175   char* bufptr = buf;
176   while (true) {
177     char* line = NS_strtok("\n", &bufptr);
178     if (!line) break;
179     if (stringToFill) {
180       stringToFill->Assign(line);
181       stringToFill = nullptr;
182     } else if (logString) {
183       gfxCriticalNote << "glxtest: " << line;
184       logString = false;
185     } else if (!strcmp(line, "VENDOR")) {
186       stringToFill = &glVendor;
187     } else if (!strcmp(line, "RENDERER")) {
188       stringToFill = &glRenderer;
189     } else if (!strcmp(line, "VERSION")) {
190       stringToFill = &glVersion;
191     } else if (!strcmp(line, "TFP")) {
192       stringToFill = &textureFromPixmap;
193     } else if (!strcmp(line, "MESA_VENDOR_ID")) {
194       stringToFill = &mesaVendor;
195     } else if (!strcmp(line, "MESA_DEVICE_ID")) {
196       stringToFill = &mesaDevice;
197     } else if (!strcmp(line, "MESA_ACCELERATED")) {
198       stringToFill = &mesaAccelerated;
199     } else if (!strcmp(line, "MESA_VRAM")) {
200       stringToFill = &adapterRam;
201     } else if (!strcmp(line, "DDX_DRIVER")) {
202       stringToFill = &ddxDriver;
203     } else if (!strcmp(line, "DRI_DRIVER")) {
204       stringToFill = &driDriver;
205     } else if (!strcmp(line, "SCREEN_INFO")) {
206       stringToFill = &screenInfo;
207     } else if (!strcmp(line, "PCI_VENDOR_ID")) {
208       stringToFill = pciVendors.AppendElement();
209     } else if (!strcmp(line, "PCI_DEVICE_ID")) {
210       stringToFill = pciDevices.AppendElement();
211     } else if (!strcmp(line, "DRM_RENDERDEVICE")) {
212       stringToFill = &drmRenderDevice;
213     } else if (!strcmp(line, "TEST_TYPE")) {
214       stringToFill = &testType;
215     } else if (!strcmp(line, "WARNING")) {
216       logString = true;
217     } else if (!strcmp(line, "ERROR")) {
218       logString = true;
219       errorLog = true;
220     }
221   }
222 
223   MOZ_ASSERT(pciDevices.Length() == pciVendors.Length(),
224              "Missing PCI vendors/devices");
225 
226   size_t pciLen = std::min(pciVendors.Length(), pciDevices.Length());
227   mHasMultipleGPUs = pciLen > 1;
228 
229   if (!strcmp(textureFromPixmap.get(), "TRUE")) mHasTextureFromPixmap = true;
230 
231   // only useful for Linux kernel version check for FGLRX driver.
232   // assumes X client == X server, which is sad.
233   struct utsname unameobj {};
234   if (uname(&unameobj) >= 0) {
235     mOS.Assign(unameobj.sysname);
236     mOSRelease.Assign(unameobj.release);
237   }
238 
239   const char* spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_GL_VENDOR");
240   if (spoofedVendor) glVendor.Assign(spoofedVendor);
241   const char* spoofedRenderer = PR_GetEnv("MOZ_GFX_SPOOF_GL_RENDERER");
242   if (spoofedRenderer) glRenderer.Assign(spoofedRenderer);
243   const char* spoofedVersion = PR_GetEnv("MOZ_GFX_SPOOF_GL_VERSION");
244   if (spoofedVersion) glVersion.Assign(spoofedVersion);
245   const char* spoofedOS = PR_GetEnv("MOZ_GFX_SPOOF_OS");
246   if (spoofedOS) mOS.Assign(spoofedOS);
247   const char* spoofedOSRelease = PR_GetEnv("MOZ_GFX_SPOOF_OS_RELEASE");
248   if (spoofedOSRelease) mOSRelease.Assign(spoofedOSRelease);
249 
250   // Scan the GL_VERSION string for the GL and driver versions.
251   nsCWhitespaceTokenizer tokenizer(glVersion);
252   while (tokenizer.hasMoreTokens()) {
253     nsCString token(tokenizer.nextToken());
254     unsigned int major = 0, minor = 0, revision = 0, patch = 0;
255     if (sscanf(token.get(), "%u.%u.%u.%u", &major, &minor, &revision, &patch) >=
256         2) {
257       // A survey of GL_VENDOR strings indicates that the first version is
258       // always the GL version, the second is usually the driver version.
259       if (mGLMajorVersion == 0) {
260         mGLMajorVersion = major;
261         mGLMinorVersion = minor;
262       } else if (mDriverVersion.IsEmpty()) {  // Not already spoofed.
263         mDriverVersion =
264             nsPrintfCString("%u.%u.%u.%u", major, minor, revision, patch);
265       }
266     }
267   }
268 
269   if (mGLMajorVersion == 0) {
270     NS_WARNING("Failed to parse GL version!");
271   }
272 
273   mDrmRenderDevice = std::move(drmRenderDevice);
274   mTestType = std::move(testType);
275 
276   // Mesa always exposes itself in the GL_VERSION string, but not always the
277   // GL_VENDOR string.
278   mIsMesa = glVersion.Find("Mesa") != -1;
279 
280   // We need to use custom driver vendor IDs for mesa so we can treat them
281   // differently than the proprietary drivers.
282   if (mIsMesa) {
283     mIsAccelerated = !mesaAccelerated.Equals("FALSE");
284     // Process software rasterizers before the DRI driver string; we may be
285     // forcing software rasterization on a DRI-accelerated X server by using
286     // LIBGL_ALWAYS_SOFTWARE or a similar restriction.
287     if (strcasestr(glRenderer.get(), "llvmpipe")) {
288       CopyUTF16toUTF8(
289           GfxDriverInfo::GetDriverVendor(DriverVendor::MesaLLVMPipe),
290           mDriverVendor);
291       mIsAccelerated = false;
292     } else if (strcasestr(glRenderer.get(), "softpipe")) {
293       CopyUTF16toUTF8(
294           GfxDriverInfo::GetDriverVendor(DriverVendor::MesaSoftPipe),
295           mDriverVendor);
296       mIsAccelerated = false;
297     } else if (strcasestr(glRenderer.get(), "software rasterizer") ||
298                !mIsAccelerated) {
299       // Fallback to reporting swrast if GLX_MESA_query_renderer tells us
300       // we're using an unaccelerated context.
301       CopyUTF16toUTF8(GfxDriverInfo::GetDriverVendor(DriverVendor::MesaSWRast),
302                       mDriverVendor);
303       mIsAccelerated = false;
304     } else if (!driDriver.IsEmpty()) {
305       mDriverVendor = nsPrintfCString("mesa/%s", driDriver.get());
306     } else {
307       // Some other mesa configuration where we couldn't get enough info.
308       NS_WARNING("Failed to detect Mesa driver being used!");
309       CopyUTF16toUTF8(GfxDriverInfo::GetDriverVendor(DriverVendor::MesaUnknown),
310                       mDriverVendor);
311     }
312 
313     if (!mesaVendor.IsEmpty()) {
314       mVendorId = mesaVendor;
315     }
316 
317     if (!mesaDevice.IsEmpty()) {
318       mDeviceId = mesaDevice;
319     }
320 
321     if (!mIsAccelerated && mVendorId.IsEmpty()) {
322       mVendorId.Assign(glVendor.get());
323     }
324 
325     if (!mIsAccelerated && mDeviceId.IsEmpty()) {
326       mDeviceId.Assign(glRenderer.get());
327     }
328   } else if (glVendor.EqualsLiteral("NVIDIA Corporation")) {
329     CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::NVIDIA),
330                     mVendorId);
331     mDriverVendor.AssignLiteral("nvidia/unknown");
332     // TODO: Use NV-CONTROL X11 extension to query Device ID and VRAM.
333   } else if (glVendor.EqualsLiteral("ATI Technologies Inc.")) {
334     CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::ATI),
335                     mVendorId);
336     mDriverVendor.AssignLiteral("ati/unknown");
337     // TODO: Look into ways to find the device ID on FGLRX.
338   } else {
339     NS_WARNING("Failed to detect GL vendor!");
340   }
341 
342   if (!screenInfo.IsEmpty()) {
343     PRInt32 start = 0;
344     PRInt32 loc = screenInfo.Find(";", PR_FALSE, start);
345     while (loc != kNotFound) {
346       int isDefault = 0;
347       nsCString line(screenInfo.get() + start, loc - start);
348       ScreenInfo info{};
349       if (sscanf(line.get(), "%ux%u:%u", &info.mWidth, &info.mHeight,
350                  &isDefault) == 3) {
351         info.mIsDefault = isDefault != 0;
352         mScreenInfo.AppendElement(info);
353       }
354 
355       start = loc + 1;
356       loc = screenInfo.Find(";", PR_FALSE, start);
357     }
358   }
359 
360   if (!adapterRam.IsEmpty()) {
361     mAdapterRAM = (uint32_t)atoi(adapterRam.get());
362   }
363 
364   // If we have the DRI driver, we can derive the vendor ID from that if needed.
365   if (mVendorId.IsEmpty() && !driDriver.IsEmpty()) {
366     const char* nvidiaDrivers[] = {"nouveau", "tegra", nullptr};
367     for (size_t i = 0; nvidiaDrivers[i]; ++i) {
368       if (driDriver.Equals(nvidiaDrivers[i])) {
369         CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::NVIDIA),
370                         mVendorId);
371         break;
372       }
373     }
374 
375     if (mVendorId.IsEmpty()) {
376       const char* intelDrivers[] = {"iris", "i915",  "i965",
377                                     "i810", "intel", nullptr};
378       for (size_t i = 0; intelDrivers[i]; ++i) {
379         if (driDriver.Equals(intelDrivers[i])) {
380           CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::Intel),
381                           mVendorId);
382           break;
383         }
384       }
385     }
386 
387     if (mVendorId.IsEmpty()) {
388       const char* amdDrivers[] = {"r600",   "r200",     "r100",
389                                   "radeon", "radeonsi", nullptr};
390       for (size_t i = 0; amdDrivers[i]; ++i) {
391         if (driDriver.Equals(amdDrivers[i])) {
392           CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::ATI),
393                           mVendorId);
394           break;
395         }
396       }
397     }
398 
399     if (mVendorId.IsEmpty()) {
400       if (driDriver.EqualsLiteral("freedreno")) {
401         CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::Qualcomm),
402                         mVendorId);
403       }
404     }
405   }
406 
407   // If we still don't have a vendor ID, we can try the PCI vendor list.
408   if (mVendorId.IsEmpty()) {
409     if (pciVendors.IsEmpty()) {
410       gfxCriticalNote << "No GPUs detected via PCI";
411     } else {
412       for (size_t i = 0; i < pciVendors.Length(); ++i) {
413         if (mVendorId.IsEmpty()) {
414           mVendorId = pciVendors[i];
415         } else if (mVendorId != pciVendors[i]) {
416           gfxCriticalNote << "More than 1 GPU vendor detected via PCI, cannot "
417                              "deduce vendor";
418           mVendorId.Truncate();
419           break;
420         }
421       }
422     }
423   }
424 
425   // If we know the vendor ID, but didn't get a device ID, we can guess from the
426   // PCI device list.
427   if (mDeviceId.IsEmpty() && !mVendorId.IsEmpty()) {
428     for (size_t i = 0; i < pciLen; ++i) {
429       if (mVendorId.Equals(pciVendors[i])) {
430         if (mDeviceId.IsEmpty()) {
431           mDeviceId = pciDevices[i];
432         } else if (mDeviceId != pciDevices[i]) {
433           gfxCriticalNote << "More than 1 GPU from same vendor detected via "
434                              "PCI, cannot deduce device";
435           mDeviceId.Truncate();
436           break;
437         }
438       }
439     }
440   }
441 
442   // Assuming we know the vendor, we should check for a secondary card.
443   if (!mVendorId.IsEmpty()) {
444     if (pciLen > 2) {
445       gfxCriticalNote
446           << "More than 2 GPUs detected via PCI, secondary GPU is arbitrary";
447     }
448     for (size_t i = 0; i < pciLen; ++i) {
449       if (!mVendorId.Equals(pciVendors[i]) ||
450           (!mDeviceId.IsEmpty() && !mDeviceId.Equals(pciDevices[i]))) {
451         mSecondaryVendorId = pciVendors[i];
452         mSecondaryDeviceId = pciDevices[i];
453         break;
454       }
455     }
456   }
457 
458   // If we couldn't choose, log them.
459   if (mVendorId.IsEmpty()) {
460     for (size_t i = 0; i < pciLen; ++i) {
461       gfxCriticalNote << "PCI candidate " << pciVendors[i].get() << "/"
462                       << pciDevices[i].get();
463     }
464   }
465 
466   // Fallback to GL_VENDOR and GL_RENDERER.
467   if (mVendorId.IsEmpty()) {
468     mVendorId.Assign(glVendor.get());
469   }
470   if (mDeviceId.IsEmpty()) {
471     mDeviceId.Assign(glRenderer.get());
472   }
473 
474   mAdapterDescription.Assign(glRenderer);
475 
476   // Make a best effort guess at whether or not we are using the XWayland compat
477   // layer. For all intents and purposes, we should otherwise believe we are
478   // using X11.
479   mIsWayland = GdkIsWaylandDisplay();
480   const char* waylandDisplay = getenv("WAYLAND_DISPLAY");
481   mIsXWayland = !mIsWayland && waylandDisplay;
482 
483   // Make a best effort guess at the desktop environment in use. Sadly there
484   // does not appear to be a standard way to do this, so we check a few
485   // different environment variables and search for relevant keywords.
486   //
487   // Note that some users manually change these values. Some applications check
488   // the environment variable like we are here, and either not work or restrict
489   // functionality. There may be some heroics we could go through to determine
490   // the truth, but for the moment, this is the best we can do. This is
491   // something to keep in mind when updating the blocklist.
492   const char* desktopEnv = getenv("XDG_CURRENT_DESKTOP");
493   if (!desktopEnv) {
494     desktopEnv = getenv("DESKTOP_SESSION");
495   }
496 
497   if (desktopEnv) {
498     std::string currentDesktop(desktopEnv);
499     for (auto& c : currentDesktop) {
500       c = std::tolower(c);
501     }
502 
503     if (currentDesktop.find("budgie") != std::string::npos) {
504       // We need to check for Budgie first, because it might incorporate GNOME
505       // into the environment variable value.
506       CopyUTF16toUTF8(
507           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Budgie),
508           mDesktopEnvironment);
509     } else if (currentDesktop.find("gnome") != std::string::npos) {
510       CopyUTF16toUTF8(
511           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::GNOME),
512           mDesktopEnvironment);
513     } else if (currentDesktop.find("kde") != std::string::npos) {
514       CopyUTF16toUTF8(
515           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::KDE),
516           mDesktopEnvironment);
517     } else if (currentDesktop.find("xfce") != std::string::npos) {
518       CopyUTF16toUTF8(
519           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::XFCE),
520           mDesktopEnvironment);
521     } else if (currentDesktop.find("cinnamon") != std::string::npos) {
522       CopyUTF16toUTF8(
523           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Cinnamon),
524           mDesktopEnvironment);
525     } else if (currentDesktop.find("enlightenment") != std::string::npos) {
526       CopyUTF16toUTF8(GfxDriverInfo::GetDesktopEnvironment(
527                           DesktopEnvironment::Enlightenment),
528                       mDesktopEnvironment);
529     } else if (currentDesktop.find("lxde") != std::string::npos ||
530                currentDesktop.find("lubuntu") != std::string::npos) {
531       CopyUTF16toUTF8(
532           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::LXDE),
533           mDesktopEnvironment);
534     } else if (currentDesktop.find("openbox") != std::string::npos) {
535       CopyUTF16toUTF8(
536           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Openbox),
537           mDesktopEnvironment);
538     } else if (currentDesktop.find("i3") != std::string::npos) {
539       CopyUTF16toUTF8(
540           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::i3),
541           mDesktopEnvironment);
542     } else if (currentDesktop.find("mate") != std::string::npos) {
543       CopyUTF16toUTF8(
544           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Mate),
545           mDesktopEnvironment);
546     } else if (currentDesktop.find("unity") != std::string::npos) {
547       CopyUTF16toUTF8(
548           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Unity),
549           mDesktopEnvironment);
550     } else if (currentDesktop.find("pantheon") != std::string::npos) {
551       CopyUTF16toUTF8(
552           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Pantheon),
553           mDesktopEnvironment);
554     } else if (currentDesktop.find("lxqt") != std::string::npos) {
555       CopyUTF16toUTF8(
556           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::LXQT),
557           mDesktopEnvironment);
558     } else if (currentDesktop.find("deepin") != std::string::npos) {
559       CopyUTF16toUTF8(
560           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Deepin),
561           mDesktopEnvironment);
562     } else if (currentDesktop.find("dwm") != std::string::npos) {
563       CopyUTF16toUTF8(
564           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Dwm),
565           mDesktopEnvironment);
566     }
567   }
568 
569   if (mDesktopEnvironment.IsEmpty()) {
570     if (getenv("GNOME_DESKTOP_SESSION_ID")) {
571       CopyUTF16toUTF8(
572           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::GNOME),
573           mDesktopEnvironment);
574     } else if (getenv("KDE_FULL_SESSION")) {
575       CopyUTF16toUTF8(
576           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::KDE),
577           mDesktopEnvironment);
578     } else if (getenv("MATE_DESKTOP_SESSION_ID")) {
579       CopyUTF16toUTF8(
580           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Mate),
581           mDesktopEnvironment);
582     } else if (getenv("LXQT_SESSION_CONFIG")) {
583       CopyUTF16toUTF8(
584           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::LXQT),
585           mDesktopEnvironment);
586     } else {
587       CopyUTF16toUTF8(
588           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Unknown),
589           mDesktopEnvironment);
590     }
591   }
592 
593   if (!ddxDriver.IsEmpty()) {
594     PRInt32 start = 0;
595     PRInt32 loc = ddxDriver.Find(";", PR_FALSE, start);
596     while (loc != kNotFound) {
597       nsCString line(ddxDriver.get() + start, loc - start);
598       mDdxDrivers.AppendElement(std::move(line));
599 
600       start = loc + 1;
601       loc = ddxDriver.Find(";", PR_FALSE, start);
602     }
603   }
604 
605   if (error || errorLog || mTestType.IsEmpty()) {
606     if (!mAdapterDescription.IsEmpty()) {
607       mAdapterDescription.AppendLiteral(" (See failure log)");
608     } else {
609       mAdapterDescription.AppendLiteral("See failure log");
610     }
611 
612     mGlxTestError = true;
613   }
614 
615   if (error) {
616     nsAutoCString msg("glxtest: process failed");
617     if (waiting_for_glxtest_process_failed) {
618       msg.AppendPrintf(" (waitpid failed with errno=%d for pid %d)",
619                        waitpid_errno, glxtest_pid);
620     }
621 
622     if (exited_with_error_code) {
623       if (exit_code == EXIT_STATUS_BUFFER_TOO_SMALL) {
624         msg.AppendLiteral(" (buffer too small)");
625       } else {
626         msg.AppendPrintf(" (exited with status %d)",
627                          WEXITSTATUS(glxtest_status));
628       }
629     }
630     if (received_signal) {
631       msg.AppendPrintf(" (received signal %d)", WTERMSIG(glxtest_status));
632     }
633 
634     gfxCriticalNote << msg.get();
635   }
636 
637   AddCrashReportAnnotations();
638 }
639 
GetGfxDriverInfo()640 const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
641   if (!sDriverInfo->Length()) {
642     // Mesa 10.0 provides the GLX_MESA_query_renderer extension, which allows us
643     // to query device IDs backing a GL context for blocklisting.
644     APPEND_TO_DRIVER_BLOCKLIST_EXT(
645         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
646         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
647         DeviceFamily::All, GfxDriverInfo::allFeatures,
648         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
649         V(10, 0, 0, 0), "FEATURE_FAILURE_OLD_MESA", "Mesa 10.0");
650 
651     // NVIDIA Mesa baseline (see bug 1714391).
652     APPEND_TO_DRIVER_BLOCKLIST_EXT(
653         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
654         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaNouveau,
655         DeviceFamily::All, GfxDriverInfo::allFeatures,
656         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
657         V(11, 0, 0, 0), "FEATURE_FAILURE_OLD_NV_MESA", "Mesa 11.0");
658 
659     // NVIDIA baseline (ported from old blocklist)
660     APPEND_TO_DRIVER_BLOCKLIST_EXT(
661         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
662         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
663         DeviceFamily::NvidiaAll, GfxDriverInfo::allFeatures,
664         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
665         V(257, 21, 0, 0), "FEATURE_FAILURE_OLD_NVIDIA", "NVIDIA 257.21");
666 
667     // fglrx baseline (chosen arbitrarily as 2013-07-22 release).
668     APPEND_TO_DRIVER_BLOCKLIST(
669         OperatingSystem::Linux, DeviceFamily::AtiAll,
670         GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
671         DRIVER_LESS_THAN, V(13, 15, 100, 1), "FEATURE_FAILURE_OLD_FGLRX",
672         "fglrx 13.15.100.1");
673 
674     ////////////////////////////////////
675     // FEATURE_WEBRENDER
676 
677     // All Mesa software drivers, see FEATURE_WEBRENDER_SOFTWARE
678     APPEND_TO_DRIVER_BLOCKLIST_EXT(
679         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
680         DesktopEnvironment::All, WindowProtocol::All,
681         DriverVendor::SoftwareMesaAll, DeviceFamily::All,
682         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
683         DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), "FEATURE_FAILURE_SOFTWARE_GL",
684         "");
685 
686     // Intel Mesa baseline, chosen arbitrarily.
687     APPEND_TO_DRIVER_BLOCKLIST(
688         OperatingSystem::Linux, DeviceFamily::IntelAll,
689         nsIGfxInfo::FEATURE_WEBRENDER,
690         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
691         V(17, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 17.0.0.0");
692 
693     APPEND_TO_DRIVER_BLOCKLIST2(
694         OperatingSystem::Linux, DeviceFamily::IntelGen7Baytrail,
695         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
696         DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0),
697         "FEATURE_FAILURE_BUG_1708682");
698 
699     // Nvidia Mesa baseline, see bug 1563859.
700     APPEND_TO_DRIVER_BLOCKLIST_EXT(
701         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
702         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
703         DeviceFamily::NvidiaAll, nsIGfxInfo::FEATURE_WEBRENDER,
704         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
705         V(18, 2, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 18.2.0.0");
706 
707     // Disable on all older Nvidia drivers due to stability issues.
708     APPEND_TO_DRIVER_BLOCKLIST_EXT(
709         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
710         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
711         DeviceFamily::NvidiaAll, nsIGfxInfo::FEATURE_WEBRENDER,
712         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_LESS_THAN, V(460, 32, 3, 0),
713         "FEATURE_FAILURE_WEBRENDER_OLD_NVIDIA", "460.32.03");
714 
715     // Disable Nvidia proprietary drivers on Wayland.
716     APPEND_TO_DRIVER_BLOCKLIST_EXT(
717         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
718         DesktopEnvironment::All, WindowProtocol::Wayland,
719         DriverVendor::NonMesaAll, DeviceFamily::NvidiaAll,
720         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
721         DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0),
722         "FEATURE_FAILURE_WEBRENDER_NVIDIA_WAYLAND",
723         "https://bugzilla.mozilla.org/show_bug.cgi?id=1646135");
724 
725     // ATI Mesa baseline, chosen arbitrarily.
726     APPEND_TO_DRIVER_BLOCKLIST_EXT(
727         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
728         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
729         DeviceFamily::AtiAll, nsIGfxInfo::FEATURE_WEBRENDER,
730         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
731         V(17, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 17.0.0.0");
732 
733     // Bug 1690568 / Bug 1393793 - Require Mesa 17.3.0+ for devices using the
734     // r600 driver to avoid shader compilation issues.
735     APPEND_TO_DRIVER_BLOCKLIST_EXT(
736         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
737         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaR600,
738         DeviceFamily::All, nsIGfxInfo::FEATURE_WEBRENDER,
739         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
740         V(17, 3, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA_R600",
741         "Mesa 17.3.0.0");
742 
743     // Disable on all ATI devices not using Mesa for now.
744     APPEND_TO_DRIVER_BLOCKLIST_EXT(
745         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
746         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
747         DeviceFamily::AtiAll, nsIGfxInfo::FEATURE_WEBRENDER,
748         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
749         V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_NO_LINUX_ATI", "");
750 
751     // Bug 1673939 - Garbled text on RS880 GPUs with Mesa drivers.
752     APPEND_TO_DRIVER_BLOCKLIST_EXT(
753         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
754         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
755         DeviceFamily::AmdR600, nsIGfxInfo::FEATURE_WEBRENDER,
756         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
757         V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_BUG_1673939",
758         "https://gitlab.freedesktop.org/mesa/mesa/-/issues/3720");
759 
760 #ifndef EARLY_BETA_OR_EARLIER
761     // Bug 1635186 - Poor performance with video playing in a background window
762     // on XWayland.
763     APPEND_TO_DRIVER_BLOCKLIST_EXT(
764         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
765         DesktopEnvironment::All, WindowProtocol::XWayland, DriverVendor::All,
766         DeviceFamily::All, nsIGfxInfo::FEATURE_WEBRENDER,
767         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
768         V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_BUG_1635186",
769         "https://bugzilla.mozilla.org/show_bug.cgi?id=1635186");
770 #endif
771 
772     ////////////////////////////////////
773     // FEATURE_WEBRENDER - ALLOWLIST
774 
775     // Intel Mesa baseline, chosen arbitrarily.
776     APPEND_TO_DRIVER_BLOCKLIST_EXT(
777         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
778         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
779         DeviceFamily::IntelRolloutWebRender, nsIGfxInfo::FEATURE_WEBRENDER,
780         nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_GREATER_THAN_OR_EQUAL,
781         V(17, 0, 0, 0), "FEATURE_ROLLOUT_INTEL_MESA", "Mesa 17.0.0.0");
782 
783     // Nvidia Mesa baseline, see bug 1563859.
784     APPEND_TO_DRIVER_BLOCKLIST_EXT(
785         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
786         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
787         DeviceFamily::NvidiaRolloutWebRender, nsIGfxInfo::FEATURE_WEBRENDER,
788         nsIGfxInfo::FEATURE_ALLOW_QUALIFIED, DRIVER_GREATER_THAN_OR_EQUAL,
789         V(18, 2, 0, 0), "FEATURE_ROLLOUT_NVIDIA_MESA", "Mesa 18.2.0.0");
790 
791     // Nvidia proprietary driver baseline, see bug 1673752.
792     APPEND_TO_DRIVER_BLOCKLIST_EXT(
793         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
794         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
795         DeviceFamily::NvidiaAll, nsIGfxInfo::FEATURE_WEBRENDER,
796         nsIGfxInfo::FEATURE_ALLOW_QUALIFIED, DRIVER_GREATER_THAN_OR_EQUAL,
797         V(460, 32, 3, 0), "FEATURE_ROLLOUT_NVIDIA_BINARY", "460.32.03");
798 
799     // ATI Mesa baseline, chosen arbitrarily.
800     APPEND_TO_DRIVER_BLOCKLIST_EXT(
801         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
802         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
803         DeviceFamily::AtiRolloutWebRender, nsIGfxInfo::FEATURE_WEBRENDER,
804         nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_GREATER_THAN_OR_EQUAL,
805         V(17, 0, 0, 0), "FEATURE_ROLLOUT_ATI_MESA", "Mesa 17.0.0.0");
806 
807     ////////////////////////////////////
808     // FEATURE_WEBRENDER_SOFTWARE - ALLOWLIST
809 #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
810     defined(__i386) || defined(__amd64__) || EARLY_BETA_OR_EARLIER
811     APPEND_TO_DRIVER_BLOCKLIST(OperatingSystem::Linux, DeviceFamily::All,
812                                nsIGfxInfo::FEATURE_WEBRENDER_SOFTWARE,
813                                nsIGfxInfo::FEATURE_ALLOW_ALWAYS,
814                                DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0),
815                                "FEATURE_ROLLOUT_SOFTWARE_WR", "");
816 #endif
817     ////////////////////////////////////
818     // FEATURE_WEBRENDER_COMPOSITOR
819     APPEND_TO_DRIVER_BLOCKLIST(
820         OperatingSystem::Linux, DeviceFamily::All,
821         nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR,
822         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
823         V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_COMPOSITOR_DISABLED", "");
824 
825     ////////////////////////////////////
826     // FEATURE_X11_EGL
827     APPEND_TO_DRIVER_BLOCKLIST(
828         OperatingSystem::Linux, DeviceFamily::All, nsIGfxInfo::FEATURE_X11_EGL,
829         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
830         V(0, 0, 0, 0), "FEATURE_FAILURE_X11_EGL_DISABLED", "");
831 
832     ////////////////////////////////////
833 
834     APPEND_TO_DRIVER_BLOCKLIST_EXT(
835         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
836         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaNouveau,
837         DeviceFamily::All, nsIGfxInfo::FEATURE_THREADSAFE_GL,
838         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
839         V(0, 0, 0, 0), "FEATURE_FAILURE_THREADSAFE_GL", "");
840   }
841   return *sDriverInfo;
842 }
843 
DoesWindowProtocolMatch(const nsAString & aBlocklistWindowProtocol,const nsAString & aWindowProtocol)844 bool GfxInfo::DoesWindowProtocolMatch(const nsAString& aBlocklistWindowProtocol,
845                                       const nsAString& aWindowProtocol) {
846   if (mIsWayland &&
847       aBlocklistWindowProtocol.Equals(
848           GfxDriverInfo::GetWindowProtocol(WindowProtocol::WaylandAll),
849           nsCaseInsensitiveStringComparator)) {
850     return true;
851   }
852   if (!mIsWayland &&
853       aBlocklistWindowProtocol.Equals(
854           GfxDriverInfo::GetWindowProtocol(WindowProtocol::X11All),
855           nsCaseInsensitiveStringComparator)) {
856     return true;
857   }
858   return GfxInfoBase::DoesWindowProtocolMatch(aBlocklistWindowProtocol,
859                                               aWindowProtocol);
860 }
861 
DoesDriverVendorMatch(const nsAString & aBlocklistVendor,const nsAString & aDriverVendor)862 bool GfxInfo::DoesDriverVendorMatch(const nsAString& aBlocklistVendor,
863                                     const nsAString& aDriverVendor) {
864   if (mIsMesa) {
865     if (aBlocklistVendor.Equals(
866             GfxDriverInfo::GetDriverVendor(DriverVendor::MesaAll),
867             nsCaseInsensitiveStringComparator)) {
868       return true;
869     }
870     if (mIsAccelerated &&
871         aBlocklistVendor.Equals(
872             GfxDriverInfo::GetDriverVendor(DriverVendor::HardwareMesaAll),
873             nsCaseInsensitiveStringComparator)) {
874       return true;
875     }
876     if (!mIsAccelerated &&
877         aBlocklistVendor.Equals(
878             GfxDriverInfo::GetDriverVendor(DriverVendor::SoftwareMesaAll),
879             nsCaseInsensitiveStringComparator)) {
880       return true;
881     }
882   }
883   if (!mIsMesa && aBlocklistVendor.Equals(
884                       GfxDriverInfo::GetDriverVendor(DriverVendor::NonMesaAll),
885                       nsCaseInsensitiveStringComparator)) {
886     return true;
887   }
888   return GfxInfoBase::DoesDriverVendorMatch(aBlocklistVendor, aDriverVendor);
889 }
890 
GetFeatureStatusImpl(int32_t aFeature,int32_t * aStatus,nsAString & aSuggestedDriverVersion,const nsTArray<GfxDriverInfo> & aDriverInfo,nsACString & aFailureId,OperatingSystem * aOS)891 nsresult GfxInfo::GetFeatureStatusImpl(
892     int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
893     const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
894     OperatingSystem* aOS /* = nullptr */)
895 
896 {
897   NS_ENSURE_ARG_POINTER(aStatus);
898   *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
899   aSuggestedDriverVersion.SetIsVoid(true);
900   OperatingSystem os = OperatingSystem::Linux;
901   if (aOS) *aOS = os;
902 
903   if (sShutdownOccurred) {
904     return NS_OK;
905   }
906 
907   GetData();
908 
909   if (mGlxTestError) {
910     // If glxtest failed, block all features by default.
911     *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
912     aFailureId = "FEATURE_FAILURE_GLXTEST_FAILED";
913     return NS_OK;
914   }
915 
916   if (mGLMajorVersion == 1) {
917     // We're on OpenGL 1. In most cases that indicates really old hardware.
918     // We better block them, rather than rely on them to fail gracefully,
919     // because they don't! see bug 696636
920     *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
921     aFailureId = "FEATURE_FAILURE_OPENGL_1";
922     return NS_OK;
923   }
924 
925   // Blocklist software GL implementations from using layers acceleration.
926   // On the test infrastructure, we'll force-enable layers acceleration.
927   if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS && !mIsAccelerated &&
928       !PR_GetEnv("MOZ_LAYERS_ALLOW_SOFTWARE_GL")) {
929     *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
930     aFailureId = "FEATURE_FAILURE_SOFTWARE_GL";
931     return NS_OK;
932   }
933 
934   if (aFeature == nsIGfxInfo::FEATURE_WEBRENDER) {
935     for (const nsCString& driver : mDdxDrivers) {
936       if (strcasestr(driver.get(), "Intel")) {
937         *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
938         aFailureId = "FEATURE_FAILURE_DDX_INTEL";
939         return NS_OK;
940       }
941     }
942   }
943 
944   return GfxInfoBase::GetFeatureStatusImpl(
945       aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
946 }
947 
948 NS_IMETHODIMP
GetD2DEnabled(bool * aEnabled)949 GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
950 
951 NS_IMETHODIMP
GetDWriteEnabled(bool * aEnabled)952 GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
953 
954 NS_IMETHODIMP
GetDWriteVersion(nsAString & aDwriteVersion)955 GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
956   return NS_ERROR_FAILURE;
957 }
958 
GetHasBattery(bool * aHasBattery)959 NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) {
960   return NS_ERROR_NOT_IMPLEMENTED;
961 }
962 
963 NS_IMETHODIMP
GetEmbeddedInFirefoxReality(bool * aEmbeddedInFirefoxReality)964 GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
965   return NS_ERROR_FAILURE;
966 }
967 
968 NS_IMETHODIMP
GetCleartypeParameters(nsAString & aCleartypeParams)969 GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
970   return NS_ERROR_FAILURE;
971 }
972 
973 NS_IMETHODIMP
GetWindowProtocol(nsAString & aWindowProtocol)974 GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
975   GetData();
976   if (mIsWayland) {
977     aWindowProtocol = GfxDriverInfo::GetWindowProtocol(WindowProtocol::Wayland);
978   } else if (mIsXWayland) {
979     aWindowProtocol =
980         GfxDriverInfo::GetWindowProtocol(WindowProtocol::XWayland);
981   } else {
982     aWindowProtocol = GfxDriverInfo::GetWindowProtocol(WindowProtocol::X11);
983   }
984   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_LINUX_WINDOW_PROTOCOL,
985                        aWindowProtocol);
986   return NS_OK;
987 }
988 
989 NS_IMETHODIMP
GetDesktopEnvironment(nsAString & aDesktopEnvironment)990 GfxInfo::GetDesktopEnvironment(nsAString& aDesktopEnvironment) {
991   GetData();
992   AppendASCIItoUTF16(mDesktopEnvironment, aDesktopEnvironment);
993   return NS_OK;
994 }
995 
996 NS_IMETHODIMP
GetTestType(nsAString & aTestType)997 GfxInfo::GetTestType(nsAString& aTestType) {
998   GetData();
999   AppendASCIItoUTF16(mTestType, aTestType);
1000   return NS_OK;
1001 }
1002 
1003 NS_IMETHODIMP
GetAdapterDescription(nsAString & aAdapterDescription)1004 GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
1005   GetData();
1006   AppendASCIItoUTF16(mAdapterDescription, aAdapterDescription);
1007   return NS_OK;
1008 }
1009 
1010 NS_IMETHODIMP
GetAdapterDescription2(nsAString & aAdapterDescription)1011 GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) {
1012   return NS_ERROR_FAILURE;
1013 }
1014 
1015 NS_IMETHODIMP
GetAdapterRAM(uint32_t * aAdapterRAM)1016 GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) {
1017   GetData();
1018   *aAdapterRAM = mAdapterRAM;
1019   return NS_OK;
1020 }
1021 
1022 NS_IMETHODIMP
GetAdapterRAM2(uint32_t * aAdapterRAM)1023 GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) { return NS_ERROR_FAILURE; }
1024 
1025 NS_IMETHODIMP
GetAdapterDriver(nsAString & aAdapterDriver)1026 GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
1027   aAdapterDriver.Truncate();
1028   return NS_OK;
1029 }
1030 
1031 NS_IMETHODIMP
GetAdapterDriver2(nsAString & aAdapterDriver)1032 GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) {
1033   return NS_ERROR_FAILURE;
1034 }
1035 
1036 NS_IMETHODIMP
GetAdapterDriverVendor(nsAString & aAdapterDriverVendor)1037 GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
1038   GetData();
1039   CopyASCIItoUTF16(mDriverVendor, aAdapterDriverVendor);
1040   return NS_OK;
1041 }
1042 
1043 NS_IMETHODIMP
GetAdapterDriverVendor2(nsAString & aAdapterDriverVendor)1044 GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) {
1045   return NS_ERROR_FAILURE;
1046 }
1047 
1048 NS_IMETHODIMP
GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)1049 GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) {
1050   GetData();
1051   CopyASCIItoUTF16(mDriverVersion, aAdapterDriverVersion);
1052   return NS_OK;
1053 }
1054 
1055 NS_IMETHODIMP
GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)1056 GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) {
1057   return NS_ERROR_FAILURE;
1058 }
1059 
1060 NS_IMETHODIMP
GetAdapterDriverDate(nsAString & aAdapterDriverDate)1061 GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) {
1062   aAdapterDriverDate.Truncate();
1063   return NS_OK;
1064 }
1065 
1066 NS_IMETHODIMP
GetAdapterDriverDate2(nsAString & aAdapterDriverDate)1067 GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) {
1068   return NS_ERROR_FAILURE;
1069 }
1070 
1071 NS_IMETHODIMP
GetAdapterVendorID(nsAString & aAdapterVendorID)1072 GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) {
1073   GetData();
1074   CopyUTF8toUTF16(mVendorId, aAdapterVendorID);
1075   return NS_OK;
1076 }
1077 
1078 NS_IMETHODIMP
GetAdapterVendorID2(nsAString & aAdapterVendorID)1079 GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
1080   GetData();
1081   CopyUTF8toUTF16(mSecondaryVendorId, aAdapterVendorID);
1082   return NS_OK;
1083 }
1084 
1085 NS_IMETHODIMP
GetAdapterDeviceID(nsAString & aAdapterDeviceID)1086 GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
1087   GetData();
1088   CopyUTF8toUTF16(mDeviceId, aAdapterDeviceID);
1089   return NS_OK;
1090 }
1091 
1092 NS_IMETHODIMP
GetAdapterDeviceID2(nsAString & aAdapterDeviceID)1093 GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
1094   GetData();
1095   CopyUTF8toUTF16(mSecondaryDeviceId, aAdapterDeviceID);
1096   return NS_OK;
1097 }
1098 
1099 NS_IMETHODIMP
GetAdapterSubsysID(nsAString & aAdapterSubsysID)1100 GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
1101   return NS_ERROR_FAILURE;
1102 }
1103 
1104 NS_IMETHODIMP
GetAdapterSubsysID2(nsAString & aAdapterSubsysID)1105 GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
1106   return NS_ERROR_FAILURE;
1107 }
1108 
1109 NS_IMETHODIMP
GetDisplayInfo(nsTArray<nsString> & aDisplayInfo)1110 GfxInfo::GetDisplayInfo(nsTArray<nsString>& aDisplayInfo) {
1111   GetData();
1112 
1113   for (auto screenInfo : mScreenInfo) {
1114     nsString infoString;
1115     infoString.AppendPrintf("%dx%d %s", screenInfo.mWidth, screenInfo.mHeight,
1116                             screenInfo.mIsDefault ? "default" : "");
1117     aDisplayInfo.AppendElement(infoString);
1118   }
1119 
1120   return aDisplayInfo.IsEmpty() ? NS_ERROR_FAILURE : NS_OK;
1121 }
1122 
1123 NS_IMETHODIMP
GetDisplayWidth(nsTArray<uint32_t> & aDisplayWidth)1124 GfxInfo::GetDisplayWidth(nsTArray<uint32_t>& aDisplayWidth) {
1125   for (auto screenInfo : mScreenInfo) {
1126     aDisplayWidth.AppendElement((uint32_t)screenInfo.mWidth);
1127   }
1128   return NS_OK;
1129 }
1130 
1131 NS_IMETHODIMP
GetDisplayHeight(nsTArray<uint32_t> & aDisplayHeight)1132 GfxInfo::GetDisplayHeight(nsTArray<uint32_t>& aDisplayHeight) {
1133   for (auto screenInfo : mScreenInfo) {
1134     aDisplayHeight.AppendElement((uint32_t)screenInfo.mHeight);
1135   }
1136   return NS_OK;
1137 }
1138 
1139 NS_IMETHODIMP
GetIsGPU2Active(bool * aIsGPU2Active)1140 GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) {
1141   // This is never the case, as the active GPU should be the primary GPU.
1142   *aIsGPU2Active = false;
1143   return NS_OK;
1144 }
1145 
1146 NS_IMETHODIMP
GetDrmRenderDevice(nsACString & aDrmRenderDevice)1147 GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
1148   GetData();
1149   aDrmRenderDevice.Assign(mDrmRenderDevice);
1150   return NS_OK;
1151 }
1152 
1153 #ifdef DEBUG
1154 
1155 // Implement nsIGfxInfoDebug
1156 // We don't support spoofing anything on Linux
1157 
SpoofVendorID(const nsAString & aVendorID)1158 NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
1159   GetData();
1160   CopyUTF16toUTF8(aVendorID, mVendorId);
1161   mIsAccelerated = true;
1162   return NS_OK;
1163 }
1164 
SpoofDeviceID(const nsAString & aDeviceID)1165 NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) {
1166   GetData();
1167   CopyUTF16toUTF8(aDeviceID, mDeviceId);
1168   return NS_OK;
1169 }
1170 
SpoofDriverVersion(const nsAString & aDriverVersion)1171 NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) {
1172   GetData();
1173   CopyUTF16toUTF8(aDriverVersion, mDriverVersion);
1174   return NS_OK;
1175 }
1176 
SpoofOSVersion(uint32_t aVersion)1177 NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
1178   // We don't support OS versioning on Linux. There's just "Linux".
1179   return NS_OK;
1180 }
1181 
FireTestProcess()1182 NS_IMETHODIMP GfxInfo::FireTestProcess() {
1183   // If the pid is zero, then we have never run the test process to query for
1184   // driver information. This would normally be run on startup, but we need to
1185   // manually invoke it for XPC shell tests.
1186   if (glxtest_pid == 0) {
1187     fire_glxtest_process();
1188   }
1189   return NS_OK;
1190 }
1191 
1192 #endif
1193 
1194 }  // namespace mozilla::widget
1195