forked from mirrors/gecko-dev
		
	 b9982073c9
			
		
	
	
		b9982073c9
		
	
	
	
	
		
			
			`swrast` is reported as fallback software driver. This happens with unknown sw-drivers (e.g. zink on lavapipe), but also when `glxtest` incorrectly detects software rendering. This can be confusing and is basically always wrong - by now it even got removed from Mesa and for years only has been used on niche setups. Make this more clear by using "mesa/software-unknown" instead. No functional change beyond reporting intended here. Differential Revision: https://phabricator.services.mozilla.com/D126052
		
			
				
	
	
		
			1176 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1176 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 | |
|  * vim: sw=2 ts=8 et :
 | |
|  */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "GfxInfo.h"
 | |
| 
 | |
| #include <cctype>
 | |
| #include <errno.h>
 | |
| #include <unistd.h>
 | |
| #include <string>
 | |
| #include <sys/types.h>
 | |
| #include <sys/utsname.h>
 | |
| #include <sys/wait.h>
 | |
| 
 | |
| #include "mozilla/gfx/Logging.h"
 | |
| #include "mozilla/SSE.h"
 | |
| #include "mozilla/Telemetry.h"
 | |
| #include "nsCRTGlue.h"
 | |
| #include "nsExceptionHandler.h"
 | |
| #include "nsPrintfCString.h"
 | |
| #include "nsUnicharUtils.h"
 | |
| #include "nsWhitespaceTokenizer.h"
 | |
| #include "prenv.h"
 | |
| #include "WidgetUtilsGtk.h"
 | |
| 
 | |
| #define EXIT_STATUS_BUFFER_TOO_SMALL 2
 | |
| #ifdef DEBUG
 | |
| bool fire_glxtest_process();
 | |
| #endif
 | |
| 
 | |
| namespace mozilla::widget {
 | |
| 
 | |
| #ifdef DEBUG
 | |
| NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
 | |
| #endif
 | |
| 
 | |
| // these global variables will be set when firing the glxtest process
 | |
| int glxtest_pipe = -1;
 | |
| pid_t glxtest_pid = 0;
 | |
| 
 | |
| nsresult GfxInfo::Init() {
 | |
|   mGLMajorVersion = 0;
 | |
|   mGLMinorVersion = 0;
 | |
|   mHasTextureFromPixmap = false;
 | |
|   mIsMesa = false;
 | |
|   mIsAccelerated = true;
 | |
|   mIsWayland = false;
 | |
|   mIsXWayland = false;
 | |
|   mHasMultipleGPUs = false;
 | |
|   mGlxTestError = false;
 | |
|   return GfxInfoBase::Init();
 | |
| }
 | |
| 
 | |
| void GfxInfo::AddCrashReportAnnotations() {
 | |
|   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID,
 | |
|                                      mVendorId);
 | |
|   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID,
 | |
|                                      mDeviceId);
 | |
|   CrashReporter::AnnotateCrashReport(
 | |
|       CrashReporter::Annotation::AdapterDriverVendor, mDriverVendor);
 | |
|   CrashReporter::AnnotateCrashReport(
 | |
|       CrashReporter::Annotation::AdapterDriverVersion, mDriverVersion);
 | |
|   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::IsWayland,
 | |
|                                      mIsWayland);
 | |
|   CrashReporter::AnnotateCrashReport(
 | |
|       CrashReporter::Annotation::DesktopEnvironment, mDesktopEnvironment);
 | |
| 
 | |
|   if (mHasMultipleGPUs) {
 | |
|     nsAutoCString note;
 | |
|     note.AppendLiteral("Has dual GPUs.");
 | |
|     if (!mSecondaryVendorId.IsEmpty()) {
 | |
|       note.AppendLiteral(" GPU #2: AdapterVendorID2: ");
 | |
|       note.Append(mSecondaryVendorId);
 | |
|       note.AppendLiteral(", AdapterDeviceID2: ");
 | |
|       note.Append(mSecondaryDeviceId);
 | |
|     }
 | |
|     CrashReporter::AppendAppNotesToCrashReport(note);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void GfxInfo::GetData() {
 | |
|   GfxInfoBase::GetData();
 | |
| 
 | |
|   // to understand this function, see bug 639842. We retrieve the OpenGL driver
 | |
|   // information in a separate process to protect against bad drivers.
 | |
| 
 | |
|   // if glxtest_pipe == -1, that means that we already read the information
 | |
|   if (glxtest_pipe == -1) return;
 | |
| 
 | |
|   enum { buf_size = 2048 };
 | |
|   char buf[buf_size];
 | |
|   ssize_t bytesread = read(glxtest_pipe, &buf,
 | |
|                            buf_size - 1);  // -1 because we'll append a zero
 | |
|   close(glxtest_pipe);
 | |
|   glxtest_pipe = -1;
 | |
| 
 | |
|   // bytesread < 0 would mean that the above read() call failed.
 | |
|   // This should never happen. If it did, the outcome would be to blocklist
 | |
|   // anyway.
 | |
|   if (bytesread < 0) {
 | |
|     bytesread = 0;
 | |
|   } else if (bytesread == buf_size - 1) {
 | |
|     gfxCriticalNote << "glxtest: read from pipe exceeded buffer size";
 | |
|   }
 | |
| 
 | |
|   // let buf be a zero-terminated string
 | |
|   buf[bytesread] = 0;
 | |
| 
 | |
|   // Wait for the glxtest process to finish. This serves 2 purposes:
 | |
|   // * avoid having a zombie glxtest process laying around
 | |
|   // * get the glxtest process status info.
 | |
|   int glxtest_status = 0;
 | |
|   bool wait_for_glxtest_process = true;
 | |
|   bool waiting_for_glxtest_process_failed = false;
 | |
|   int waitpid_errno = 0;
 | |
|   while (wait_for_glxtest_process) {
 | |
|     wait_for_glxtest_process = false;
 | |
|     if (waitpid(glxtest_pid, &glxtest_status, 0) == -1) {
 | |
|       waitpid_errno = errno;
 | |
|       if (waitpid_errno == EINTR) {
 | |
|         wait_for_glxtest_process = true;
 | |
|       } else {
 | |
|         // Bug 718629
 | |
|         // ECHILD happens when the glxtest process got reaped got reaped after a
 | |
|         // PR_CreateProcess as per bug 227246. This shouldn't matter, as we
 | |
|         // still seem to get the data from the pipe, and if we didn't, the
 | |
|         // outcome would be to blocklist anyway.
 | |
|         waiting_for_glxtest_process_failed = (waitpid_errno != ECHILD);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   int exit_code = EXIT_FAILURE;
 | |
|   bool exited_with_error_code = false;
 | |
|   if (!waiting_for_glxtest_process_failed && WIFEXITED(glxtest_status)) {
 | |
|     exit_code = WEXITSTATUS(glxtest_status);
 | |
|     exited_with_error_code = exit_code != EXIT_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   bool received_signal =
 | |
|       !waiting_for_glxtest_process_failed && WIFSIGNALED(glxtest_status);
 | |
| 
 | |
|   bool error = waiting_for_glxtest_process_failed || exited_with_error_code ||
 | |
|                received_signal;
 | |
|   bool errorLog = false;
 | |
| 
 | |
|   nsCString glVendor;
 | |
|   nsCString glRenderer;
 | |
|   nsCString glVersion;
 | |
|   nsCString textureFromPixmap;
 | |
|   nsCString testType;
 | |
| 
 | |
|   // Available if GLX_MESA_query_renderer is supported.
 | |
|   nsCString mesaVendor;
 | |
|   nsCString mesaDevice;
 | |
|   nsCString mesaAccelerated;
 | |
|   // Available if using a DRI-based libGL stack.
 | |
|   nsCString driDriver;
 | |
|   nsCString screenInfo;
 | |
|   nsCString adapterRam;
 | |
| 
 | |
|   nsCString drmRenderDevice;
 | |
| 
 | |
|   AutoTArray<nsCString, 2> pciVendors;
 | |
|   AutoTArray<nsCString, 2> pciDevices;
 | |
| 
 | |
|   nsCString* stringToFill = nullptr;
 | |
|   bool logString = false;
 | |
| 
 | |
|   char* bufptr = buf;
 | |
|   while (true) {
 | |
|     char* line = NS_strtok("\n", &bufptr);
 | |
|     if (!line) break;
 | |
|     if (stringToFill) {
 | |
|       stringToFill->Assign(line);
 | |
|       stringToFill = nullptr;
 | |
|     } else if (logString) {
 | |
|       gfxCriticalNote << "glxtest: " << line;
 | |
|       logString = false;
 | |
|     } else if (!strcmp(line, "VENDOR")) {
 | |
|       stringToFill = &glVendor;
 | |
|     } else if (!strcmp(line, "RENDERER")) {
 | |
|       stringToFill = &glRenderer;
 | |
|     } else if (!strcmp(line, "VERSION")) {
 | |
|       stringToFill = &glVersion;
 | |
|     } else if (!strcmp(line, "TFP")) {
 | |
|       stringToFill = &textureFromPixmap;
 | |
|     } else if (!strcmp(line, "MESA_VENDOR_ID")) {
 | |
|       stringToFill = &mesaVendor;
 | |
|     } else if (!strcmp(line, "MESA_DEVICE_ID")) {
 | |
|       stringToFill = &mesaDevice;
 | |
|     } else if (!strcmp(line, "MESA_ACCELERATED")) {
 | |
|       stringToFill = &mesaAccelerated;
 | |
|     } else if (!strcmp(line, "MESA_VRAM")) {
 | |
|       stringToFill = &adapterRam;
 | |
|     } else if (!strcmp(line, "DRI_DRIVER")) {
 | |
|       stringToFill = &driDriver;
 | |
|     } else if (!strcmp(line, "SCREEN_INFO")) {
 | |
|       stringToFill = &screenInfo;
 | |
|     } else if (!strcmp(line, "PCI_VENDOR_ID")) {
 | |
|       stringToFill = pciVendors.AppendElement();
 | |
|     } else if (!strcmp(line, "PCI_DEVICE_ID")) {
 | |
|       stringToFill = pciDevices.AppendElement();
 | |
|     } else if (!strcmp(line, "DRM_RENDERDEVICE")) {
 | |
|       stringToFill = &drmRenderDevice;
 | |
|     } else if (!strcmp(line, "TEST_TYPE")) {
 | |
|       stringToFill = &testType;
 | |
|     } else if (!strcmp(line, "WARNING")) {
 | |
|       logString = true;
 | |
|     } else if (!strcmp(line, "ERROR")) {
 | |
|       logString = true;
 | |
|       errorLog = true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   MOZ_ASSERT(pciDevices.Length() == pciVendors.Length(),
 | |
|              "Missing PCI vendors/devices");
 | |
| 
 | |
|   size_t pciLen = std::min(pciVendors.Length(), pciDevices.Length());
 | |
|   mHasMultipleGPUs = pciLen > 1;
 | |
| 
 | |
|   if (!strcmp(textureFromPixmap.get(), "TRUE")) mHasTextureFromPixmap = true;
 | |
| 
 | |
|   // only useful for Linux kernel version check for FGLRX driver.
 | |
|   // assumes X client == X server, which is sad.
 | |
|   struct utsname unameobj {};
 | |
|   if (uname(&unameobj) >= 0) {
 | |
|     mOS.Assign(unameobj.sysname);
 | |
|     mOSRelease.Assign(unameobj.release);
 | |
|   }
 | |
| 
 | |
|   const char* spoofedVendor = PR_GetEnv("MOZ_GFX_SPOOF_GL_VENDOR");
 | |
|   if (spoofedVendor) glVendor.Assign(spoofedVendor);
 | |
|   const char* spoofedRenderer = PR_GetEnv("MOZ_GFX_SPOOF_GL_RENDERER");
 | |
|   if (spoofedRenderer) glRenderer.Assign(spoofedRenderer);
 | |
|   const char* spoofedVersion = PR_GetEnv("MOZ_GFX_SPOOF_GL_VERSION");
 | |
|   if (spoofedVersion) glVersion.Assign(spoofedVersion);
 | |
|   const char* spoofedOS = PR_GetEnv("MOZ_GFX_SPOOF_OS");
 | |
|   if (spoofedOS) mOS.Assign(spoofedOS);
 | |
|   const char* spoofedOSRelease = PR_GetEnv("MOZ_GFX_SPOOF_OS_RELEASE");
 | |
|   if (spoofedOSRelease) mOSRelease.Assign(spoofedOSRelease);
 | |
| 
 | |
|   // Scan the GL_VERSION string for the GL and driver versions.
 | |
|   nsCWhitespaceTokenizer tokenizer(glVersion);
 | |
|   while (tokenizer.hasMoreTokens()) {
 | |
|     nsCString token(tokenizer.nextToken());
 | |
|     unsigned int major = 0, minor = 0, revision = 0, patch = 0;
 | |
|     if (sscanf(token.get(), "%u.%u.%u.%u", &major, &minor, &revision, &patch) >=
 | |
|         2) {
 | |
|       // A survey of GL_VENDOR strings indicates that the first version is
 | |
|       // always the GL version, the second is usually the driver version.
 | |
|       if (mGLMajorVersion == 0) {
 | |
|         mGLMajorVersion = major;
 | |
|         mGLMinorVersion = minor;
 | |
|       } else if (mDriverVersion.IsEmpty()) {  // Not already spoofed.
 | |
|         mDriverVersion =
 | |
|             nsPrintfCString("%u.%u.%u.%u", major, minor, revision, patch);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (mGLMajorVersion == 0) {
 | |
|     NS_WARNING("Failed to parse GL version!");
 | |
|   }
 | |
| 
 | |
|   mDrmRenderDevice = std::move(drmRenderDevice);
 | |
|   mTestType = std::move(testType);
 | |
| 
 | |
|   // Mesa always exposes itself in the GL_VERSION string, but not always the
 | |
|   // GL_VENDOR string.
 | |
|   mIsMesa = glVersion.Find("Mesa") != -1;
 | |
| 
 | |
|   // We need to use custom driver vendor IDs for mesa so we can treat them
 | |
|   // differently than the proprietary drivers.
 | |
|   if (mIsMesa) {
 | |
|     mIsAccelerated = !mesaAccelerated.Equals("FALSE");
 | |
|     // Process software rasterizers before the DRI driver string; we may be
 | |
|     // forcing software rasterization on a DRI-accelerated X server by using
 | |
|     // LIBGL_ALWAYS_SOFTWARE or a similar restriction.
 | |
|     if (strcasestr(glRenderer.get(), "llvmpipe")) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDriverVendor(DriverVendor::MesaLLVMPipe),
 | |
|           mDriverVendor);
 | |
|       mIsAccelerated = false;
 | |
|     } else if (strcasestr(glRenderer.get(), "softpipe")) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDriverVendor(DriverVendor::MesaSoftPipe),
 | |
|           mDriverVendor);
 | |
|       mIsAccelerated = false;
 | |
|     } else if (strcasestr(glRenderer.get(), "software rasterizer")) {
 | |
|       CopyUTF16toUTF8(GfxDriverInfo::GetDriverVendor(DriverVendor::MesaSWRast),
 | |
|                       mDriverVendor);
 | |
|       mIsAccelerated = false;
 | |
|     } else if (!mIsAccelerated) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDriverVendor(DriverVendor::MesaSWUnknown),
 | |
|           mDriverVendor);
 | |
|     } else if (!driDriver.IsEmpty()) {
 | |
|       mDriverVendor = nsPrintfCString("mesa/%s", driDriver.get());
 | |
|     } else {
 | |
|       // Some other mesa configuration where we couldn't get enough info.
 | |
|       NS_WARNING("Failed to detect Mesa driver being used!");
 | |
|       CopyUTF16toUTF8(GfxDriverInfo::GetDriverVendor(DriverVendor::MesaUnknown),
 | |
|                       mDriverVendor);
 | |
|     }
 | |
| 
 | |
|     if (!mesaVendor.IsEmpty()) {
 | |
|       mVendorId = mesaVendor;
 | |
|     }
 | |
| 
 | |
|     if (!mesaDevice.IsEmpty()) {
 | |
|       mDeviceId = mesaDevice;
 | |
|     }
 | |
| 
 | |
|     if (!mIsAccelerated && mVendorId.IsEmpty()) {
 | |
|       mVendorId.Assign(glVendor.get());
 | |
|     }
 | |
| 
 | |
|     if (!mIsAccelerated && mDeviceId.IsEmpty()) {
 | |
|       mDeviceId.Assign(glRenderer.get());
 | |
|     }
 | |
|   } else if (glVendor.EqualsLiteral("NVIDIA Corporation")) {
 | |
|     CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::NVIDIA),
 | |
|                     mVendorId);
 | |
|     mDriverVendor.AssignLiteral("nvidia/unknown");
 | |
|     // TODO: Use NV-CONTROL X11 extension to query Device ID and VRAM.
 | |
|   } else if (glVendor.EqualsLiteral("ATI Technologies Inc.")) {
 | |
|     CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::ATI),
 | |
|                     mVendorId);
 | |
|     mDriverVendor.AssignLiteral("ati/unknown");
 | |
|     // TODO: Look into ways to find the device ID on FGLRX.
 | |
|   } else {
 | |
|     NS_WARNING("Failed to detect GL vendor!");
 | |
|   }
 | |
| 
 | |
|   if (!screenInfo.IsEmpty()) {
 | |
|     PRInt32 start = 0;
 | |
|     PRInt32 loc = screenInfo.Find(";", PR_FALSE, start);
 | |
|     while (loc != kNotFound) {
 | |
|       int isDefault = 0;
 | |
|       nsCString line(screenInfo.get() + start, loc - start);
 | |
|       ScreenInfo info{};
 | |
|       if (sscanf(line.get(), "%ux%u:%u", &info.mWidth, &info.mHeight,
 | |
|                  &isDefault) == 3) {
 | |
|         info.mIsDefault = isDefault != 0;
 | |
|         mScreenInfo.AppendElement(info);
 | |
|       }
 | |
| 
 | |
|       start = loc + 1;
 | |
|       loc = screenInfo.Find(";", PR_FALSE, start);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!adapterRam.IsEmpty()) {
 | |
|     mAdapterRAM = (uint32_t)atoi(adapterRam.get());
 | |
|   }
 | |
| 
 | |
|   // If we have the DRI driver, we can derive the vendor ID from that if needed.
 | |
|   if (mVendorId.IsEmpty() && !driDriver.IsEmpty()) {
 | |
|     const char* nvidiaDrivers[] = {"nouveau", "tegra", nullptr};
 | |
|     for (size_t i = 0; nvidiaDrivers[i]; ++i) {
 | |
|       if (driDriver.Equals(nvidiaDrivers[i])) {
 | |
|         CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::NVIDIA),
 | |
|                         mVendorId);
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (mVendorId.IsEmpty()) {
 | |
|       const char* intelDrivers[] = {"iris", "i915",  "i965",
 | |
|                                     "i810", "intel", nullptr};
 | |
|       for (size_t i = 0; intelDrivers[i]; ++i) {
 | |
|         if (driDriver.Equals(intelDrivers[i])) {
 | |
|           CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::Intel),
 | |
|                           mVendorId);
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (mVendorId.IsEmpty()) {
 | |
|       const char* amdDrivers[] = {"r600",   "r200",     "r100",
 | |
|                                   "radeon", "radeonsi", nullptr};
 | |
|       for (size_t i = 0; amdDrivers[i]; ++i) {
 | |
|         if (driDriver.Equals(amdDrivers[i])) {
 | |
|           CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::ATI),
 | |
|                           mVendorId);
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (mVendorId.IsEmpty()) {
 | |
|       if (driDriver.EqualsLiteral("freedreno")) {
 | |
|         CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::Qualcomm),
 | |
|                         mVendorId);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // If we still don't have a vendor ID, we can try the PCI vendor list.
 | |
|   if (mVendorId.IsEmpty()) {
 | |
|     if (pciVendors.IsEmpty()) {
 | |
|       gfxCriticalNote << "No GPUs detected via PCI";
 | |
|     } else {
 | |
|       for (size_t i = 0; i < pciVendors.Length(); ++i) {
 | |
|         if (mVendorId.IsEmpty()) {
 | |
|           mVendorId = pciVendors[i];
 | |
|         } else if (mVendorId != pciVendors[i]) {
 | |
|           gfxCriticalNote << "More than 1 GPU vendor detected via PCI, cannot "
 | |
|                              "deduce vendor";
 | |
|           mVendorId.Truncate();
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // If we know the vendor ID, but didn't get a device ID, we can guess from the
 | |
|   // PCI device list.
 | |
|   if (mDeviceId.IsEmpty() && !mVendorId.IsEmpty()) {
 | |
|     for (size_t i = 0; i < pciLen; ++i) {
 | |
|       if (mVendorId.Equals(pciVendors[i])) {
 | |
|         if (mDeviceId.IsEmpty()) {
 | |
|           mDeviceId = pciDevices[i];
 | |
|         } else if (mDeviceId != pciDevices[i]) {
 | |
|           gfxCriticalNote << "More than 1 GPU from same vendor detected via "
 | |
|                              "PCI, cannot deduce device";
 | |
|           mDeviceId.Truncate();
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Assuming we know the vendor, we should check for a secondary card.
 | |
|   if (!mVendorId.IsEmpty()) {
 | |
|     if (pciLen > 2) {
 | |
|       gfxCriticalNote
 | |
|           << "More than 2 GPUs detected via PCI, secondary GPU is arbitrary";
 | |
|     }
 | |
|     for (size_t i = 0; i < pciLen; ++i) {
 | |
|       if (!mVendorId.Equals(pciVendors[i]) ||
 | |
|           (!mDeviceId.IsEmpty() && !mDeviceId.Equals(pciDevices[i]))) {
 | |
|         mSecondaryVendorId = pciVendors[i];
 | |
|         mSecondaryDeviceId = pciDevices[i];
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // If we couldn't choose, log them.
 | |
|   if (mVendorId.IsEmpty()) {
 | |
|     for (size_t i = 0; i < pciLen; ++i) {
 | |
|       gfxCriticalNote << "PCI candidate " << pciVendors[i].get() << "/"
 | |
|                       << pciDevices[i].get();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Fallback to GL_VENDOR and GL_RENDERER.
 | |
|   if (mVendorId.IsEmpty()) {
 | |
|     mVendorId.Assign(glVendor.get());
 | |
|   }
 | |
|   if (mDeviceId.IsEmpty()) {
 | |
|     mDeviceId.Assign(glRenderer.get());
 | |
|   }
 | |
| 
 | |
|   mAdapterDescription.Assign(glRenderer);
 | |
| 
 | |
|   // Make a best effort guess at whether or not we are using the XWayland compat
 | |
|   // layer. For all intents and purposes, we should otherwise believe we are
 | |
|   // using X11.
 | |
|   mIsWayland = GdkIsWaylandDisplay();
 | |
|   const char* waylandDisplay = getenv("WAYLAND_DISPLAY");
 | |
|   mIsXWayland = !mIsWayland && waylandDisplay;
 | |
| 
 | |
|   // Make a best effort guess at the desktop environment in use. Sadly there
 | |
|   // does not appear to be a standard way to do this, so we check a few
 | |
|   // different environment variables and search for relevant keywords.
 | |
|   //
 | |
|   // Note that some users manually change these values. Some applications check
 | |
|   // the environment variable like we are here, and either not work or restrict
 | |
|   // functionality. There may be some heroics we could go through to determine
 | |
|   // the truth, but for the moment, this is the best we can do. This is
 | |
|   // something to keep in mind when updating the blocklist.
 | |
|   const char* desktopEnv = getenv("XDG_CURRENT_DESKTOP");
 | |
|   if (!desktopEnv) {
 | |
|     desktopEnv = getenv("DESKTOP_SESSION");
 | |
|   }
 | |
| 
 | |
|   if (desktopEnv) {
 | |
|     std::string currentDesktop(desktopEnv);
 | |
|     for (auto& c : currentDesktop) {
 | |
|       c = std::tolower(c);
 | |
|     }
 | |
| 
 | |
|     if (currentDesktop.find("budgie") != std::string::npos) {
 | |
|       // We need to check for Budgie first, because it might incorporate GNOME
 | |
|       // into the environment variable value.
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Budgie),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("gnome") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::GNOME),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("kde") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::KDE),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("xfce") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::XFCE),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("cinnamon") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Cinnamon),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("enlightenment") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(GfxDriverInfo::GetDesktopEnvironment(
 | |
|                           DesktopEnvironment::Enlightenment),
 | |
|                       mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("lxde") != std::string::npos ||
 | |
|                currentDesktop.find("lubuntu") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::LXDE),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("openbox") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Openbox),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("i3") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::i3),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("mate") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Mate),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("unity") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Unity),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("pantheon") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Pantheon),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("lxqt") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::LXQT),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("deepin") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Deepin),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (currentDesktop.find("dwm") != std::string::npos) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Dwm),
 | |
|           mDesktopEnvironment);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (mDesktopEnvironment.IsEmpty()) {
 | |
|     if (getenv("GNOME_DESKTOP_SESSION_ID")) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::GNOME),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (getenv("KDE_FULL_SESSION")) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::KDE),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (getenv("MATE_DESKTOP_SESSION_ID")) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Mate),
 | |
|           mDesktopEnvironment);
 | |
|     } else if (getenv("LXQT_SESSION_CONFIG")) {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::LXQT),
 | |
|           mDesktopEnvironment);
 | |
|     } else {
 | |
|       CopyUTF16toUTF8(
 | |
|           GfxDriverInfo::GetDesktopEnvironment(DesktopEnvironment::Unknown),
 | |
|           mDesktopEnvironment);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (error || errorLog || mTestType.IsEmpty()) {
 | |
|     if (!mAdapterDescription.IsEmpty()) {
 | |
|       mAdapterDescription.AppendLiteral(" (See failure log)");
 | |
|     } else {
 | |
|       mAdapterDescription.AppendLiteral("See failure log");
 | |
|     }
 | |
| 
 | |
|     mGlxTestError = true;
 | |
|   }
 | |
| 
 | |
|   if (error) {
 | |
|     nsAutoCString msg("glxtest: process failed");
 | |
|     if (waiting_for_glxtest_process_failed) {
 | |
|       msg.AppendPrintf(" (waitpid failed with errno=%d for pid %d)",
 | |
|                        waitpid_errno, glxtest_pid);
 | |
|     }
 | |
| 
 | |
|     if (exited_with_error_code) {
 | |
|       if (exit_code == EXIT_STATUS_BUFFER_TOO_SMALL) {
 | |
|         msg.AppendLiteral(" (buffer too small)");
 | |
|       } else {
 | |
|         msg.AppendPrintf(" (exited with status %d)",
 | |
|                          WEXITSTATUS(glxtest_status));
 | |
|       }
 | |
|     }
 | |
|     if (received_signal) {
 | |
|       msg.AppendPrintf(" (received signal %d)", WTERMSIG(glxtest_status));
 | |
|     }
 | |
| 
 | |
|     gfxCriticalNote << msg.get();
 | |
|   }
 | |
| 
 | |
|   AddCrashReportAnnotations();
 | |
| }
 | |
| 
 | |
| const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
 | |
|   if (!sDriverInfo->Length()) {
 | |
|     // Mesa 10.0 provides the GLX_MESA_query_renderer extension, which allows us
 | |
|     // to query device IDs backing a GL context for blocklisting.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
 | |
|         DeviceFamily::All, GfxDriverInfo::allFeatures,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
 | |
|         V(10, 0, 0, 0), "FEATURE_FAILURE_OLD_MESA", "Mesa 10.0");
 | |
| 
 | |
|     // NVIDIA Mesa baseline (see bug 1714391).
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaNouveau,
 | |
|         DeviceFamily::All, GfxDriverInfo::allFeatures,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
 | |
|         V(11, 0, 0, 0), "FEATURE_FAILURE_OLD_NV_MESA", "Mesa 11.0");
 | |
| 
 | |
|     // NVIDIA baseline (ported from old blocklist)
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
 | |
|         DeviceFamily::NvidiaAll, GfxDriverInfo::allFeatures,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
 | |
|         V(257, 21, 0, 0), "FEATURE_FAILURE_OLD_NVIDIA", "NVIDIA 257.21");
 | |
| 
 | |
|     // fglrx baseline (chosen arbitrarily as 2013-07-22 release).
 | |
|     APPEND_TO_DRIVER_BLOCKLIST(
 | |
|         OperatingSystem::Linux, DeviceFamily::AtiAll,
 | |
|         GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
 | |
|         DRIVER_LESS_THAN, V(13, 15, 100, 1), "FEATURE_FAILURE_OLD_FGLRX",
 | |
|         "fglrx 13.15.100.1");
 | |
| 
 | |
|     ////////////////////////////////////
 | |
|     // FEATURE_WEBRENDER
 | |
| 
 | |
|     // All Mesa software drivers, they should get Software WebRender instead.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All,
 | |
|         DriverVendor::SoftwareMesaAll, DeviceFamily::All,
 | |
|         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
 | |
|         DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), "FEATURE_FAILURE_SOFTWARE_GL",
 | |
|         "");
 | |
| 
 | |
|     // Intel Mesa baseline, chosen arbitrarily.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST(
 | |
|         OperatingSystem::Linux, DeviceFamily::IntelAll,
 | |
|         nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
 | |
|         V(17, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 17.0.0.0");
 | |
| 
 | |
|     APPEND_TO_DRIVER_BLOCKLIST2(
 | |
|         OperatingSystem::Linux, DeviceFamily::IntelGen7Baytrail,
 | |
|         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
 | |
|         DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0),
 | |
|         "FEATURE_FAILURE_BUG_1708682");
 | |
| 
 | |
|     // Nvidia Mesa baseline, see bug 1563859.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
 | |
|         DeviceFamily::NvidiaAll, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
 | |
|         V(18, 2, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 18.2.0.0");
 | |
| 
 | |
|     // Disable on all older Nvidia drivers due to stability issues.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
 | |
|         DeviceFamily::NvidiaAll, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_LESS_THAN, V(460, 32, 3, 0),
 | |
|         "FEATURE_FAILURE_WEBRENDER_OLD_NVIDIA", "460.32.03");
 | |
| 
 | |
|     // Disable Nvidia proprietary drivers on Wayland.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::Wayland,
 | |
|         DriverVendor::NonMesaAll, DeviceFamily::NvidiaAll,
 | |
|         nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_BLOCKED_DEVICE,
 | |
|         DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0),
 | |
|         "FEATURE_FAILURE_WEBRENDER_NVIDIA_WAYLAND",
 | |
|         "https://bugzilla.mozilla.org/show_bug.cgi?id=1646135");
 | |
| 
 | |
|     // ATI Mesa baseline, chosen arbitrarily.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
 | |
|         DeviceFamily::AtiAll, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
 | |
|         V(17, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 17.0.0.0");
 | |
| 
 | |
|     // Bug 1690568 / Bug 1393793 - Require Mesa 17.3.0+ for devices using the
 | |
|     // r600 driver to avoid shader compilation issues.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaR600,
 | |
|         DeviceFamily::All, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
 | |
|         V(17, 3, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA_R600",
 | |
|         "Mesa 17.3.0.0");
 | |
| 
 | |
|     // Disable on all ATI devices not using Mesa for now.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
 | |
|         DeviceFamily::AtiAll, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
 | |
|         V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_NO_LINUX_ATI", "");
 | |
| 
 | |
|     // Bug 1673939 - Garbled text on RS880 GPUs with Mesa drivers.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
 | |
|         DeviceFamily::AmdR600, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
 | |
|         V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_BUG_1673939",
 | |
|         "https://gitlab.freedesktop.org/mesa/mesa/-/issues/3720");
 | |
| 
 | |
| #ifndef EARLY_BETA_OR_EARLIER
 | |
|     // Bug 1635186 - Poor performance with video playing in a background window
 | |
|     // on XWayland.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::XWayland, DriverVendor::All,
 | |
|         DeviceFamily::All, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
 | |
|         V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_BUG_1635186",
 | |
|         "https://bugzilla.mozilla.org/show_bug.cgi?id=1635186");
 | |
| #endif
 | |
| 
 | |
|     ////////////////////////////////////
 | |
|     // FEATURE_WEBRENDER - ALLOWLIST
 | |
| 
 | |
|     // Intel Mesa baseline, chosen arbitrarily.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
 | |
|         DeviceFamily::IntelRolloutWebRender, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_GREATER_THAN_OR_EQUAL,
 | |
|         V(17, 0, 0, 0), "FEATURE_ROLLOUT_INTEL_MESA", "Mesa 17.0.0.0");
 | |
| 
 | |
|     // Nvidia Mesa baseline, see bug 1563859.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
 | |
|         DeviceFamily::NvidiaRolloutWebRender, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_ALLOW_QUALIFIED, DRIVER_GREATER_THAN_OR_EQUAL,
 | |
|         V(18, 2, 0, 0), "FEATURE_ROLLOUT_NVIDIA_MESA", "Mesa 18.2.0.0");
 | |
| 
 | |
|     // Nvidia proprietary driver baseline, see bug 1673752.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
 | |
|         DeviceFamily::NvidiaAll, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_ALLOW_QUALIFIED, DRIVER_GREATER_THAN_OR_EQUAL,
 | |
|         V(460, 32, 3, 0), "FEATURE_ROLLOUT_NVIDIA_BINARY", "460.32.03");
 | |
| 
 | |
|     // ATI Mesa baseline, chosen arbitrarily.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
 | |
|         DeviceFamily::AtiRolloutWebRender, nsIGfxInfo::FEATURE_WEBRENDER,
 | |
|         nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_GREATER_THAN_OR_EQUAL,
 | |
|         V(17, 0, 0, 0), "FEATURE_ROLLOUT_ATI_MESA", "Mesa 17.0.0.0");
 | |
| 
 | |
|     ////////////////////////////////////
 | |
|     // FEATURE_WEBRENDER_COMPOSITOR
 | |
|     APPEND_TO_DRIVER_BLOCKLIST(
 | |
|         OperatingSystem::Linux, DeviceFamily::All,
 | |
|         nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
 | |
|         V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_COMPOSITOR_DISABLED", "");
 | |
| 
 | |
|     ////////////////////////////////////
 | |
|     // FEATURE_X11_EGL
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll,
 | |
|         DeviceFamily::All, nsIGfxInfo::FEATURE_X11_EGL,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
 | |
|         V(21, 0, 0, 0), "FEATURE_ROLLOUT_X11_EGL_MESA", "Mesa 21.0.0.0");
 | |
| 
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
 | |
|         DeviceFamily::NvidiaAll, nsIGfxInfo::FEATURE_X11_EGL,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN,
 | |
|         V(470, 0, 0, 0), "FEATURE_ROLLOUT_X11_EGL_NVIDIA_BINARY", "470.0.0");
 | |
| 
 | |
|     // Disable on all AMD devices not using Mesa.
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::NonMesaAll,
 | |
|         DeviceFamily::AtiAll, nsIGfxInfo::FEATURE_X11_EGL,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
 | |
|         V(0, 0, 0, 0), "FEATURE_FAILURE_X11_EGL_NO_LINUX_ATI", "");
 | |
| 
 | |
|     ////////////////////////////////////
 | |
| 
 | |
|     APPEND_TO_DRIVER_BLOCKLIST_EXT(
 | |
|         OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,
 | |
|         DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaNouveau,
 | |
|         DeviceFamily::All, nsIGfxInfo::FEATURE_THREADSAFE_GL,
 | |
|         nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED,
 | |
|         V(0, 0, 0, 0), "FEATURE_FAILURE_THREADSAFE_GL", "");
 | |
|   }
 | |
|   return *sDriverInfo;
 | |
| }
 | |
| 
 | |
| bool GfxInfo::DoesWindowProtocolMatch(const nsAString& aBlocklistWindowProtocol,
 | |
|                                       const nsAString& aWindowProtocol) {
 | |
|   if (mIsWayland &&
 | |
|       aBlocklistWindowProtocol.Equals(
 | |
|           GfxDriverInfo::GetWindowProtocol(WindowProtocol::WaylandAll),
 | |
|           nsCaseInsensitiveStringComparator)) {
 | |
|     return true;
 | |
|   }
 | |
|   if (!mIsWayland &&
 | |
|       aBlocklistWindowProtocol.Equals(
 | |
|           GfxDriverInfo::GetWindowProtocol(WindowProtocol::X11All),
 | |
|           nsCaseInsensitiveStringComparator)) {
 | |
|     return true;
 | |
|   }
 | |
|   return GfxInfoBase::DoesWindowProtocolMatch(aBlocklistWindowProtocol,
 | |
|                                               aWindowProtocol);
 | |
| }
 | |
| 
 | |
| bool GfxInfo::DoesDriverVendorMatch(const nsAString& aBlocklistVendor,
 | |
|                                     const nsAString& aDriverVendor) {
 | |
|   if (mIsMesa) {
 | |
|     if (aBlocklistVendor.Equals(
 | |
|             GfxDriverInfo::GetDriverVendor(DriverVendor::MesaAll),
 | |
|             nsCaseInsensitiveStringComparator)) {
 | |
|       return true;
 | |
|     }
 | |
|     if (mIsAccelerated &&
 | |
|         aBlocklistVendor.Equals(
 | |
|             GfxDriverInfo::GetDriverVendor(DriverVendor::HardwareMesaAll),
 | |
|             nsCaseInsensitiveStringComparator)) {
 | |
|       return true;
 | |
|     }
 | |
|     if (!mIsAccelerated &&
 | |
|         aBlocklistVendor.Equals(
 | |
|             GfxDriverInfo::GetDriverVendor(DriverVendor::SoftwareMesaAll),
 | |
|             nsCaseInsensitiveStringComparator)) {
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
|   if (!mIsMesa && aBlocklistVendor.Equals(
 | |
|                       GfxDriverInfo::GetDriverVendor(DriverVendor::NonMesaAll),
 | |
|                       nsCaseInsensitiveStringComparator)) {
 | |
|     return true;
 | |
|   }
 | |
|   return GfxInfoBase::DoesDriverVendorMatch(aBlocklistVendor, aDriverVendor);
 | |
| }
 | |
| 
 | |
| nsresult GfxInfo::GetFeatureStatusImpl(
 | |
|     int32_t aFeature, int32_t* aStatus, nsAString& aSuggestedDriverVersion,
 | |
|     const nsTArray<GfxDriverInfo>& aDriverInfo, nsACString& aFailureId,
 | |
|     OperatingSystem* aOS /* = nullptr */)
 | |
| 
 | |
| {
 | |
|   NS_ENSURE_ARG_POINTER(aStatus);
 | |
|   *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
 | |
|   aSuggestedDriverVersion.SetIsVoid(true);
 | |
|   OperatingSystem os = OperatingSystem::Linux;
 | |
|   if (aOS) *aOS = os;
 | |
| 
 | |
|   if (sShutdownOccurred) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   GetData();
 | |
| 
 | |
|   if (mGlxTestError) {
 | |
|     // If glxtest failed, block all features by default.
 | |
|     *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
 | |
|     aFailureId = "FEATURE_FAILURE_GLXTEST_FAILED";
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   if (mGLMajorVersion == 1) {
 | |
|     // We're on OpenGL 1. In most cases that indicates really old hardware.
 | |
|     // We better block them, rather than rely on them to fail gracefully,
 | |
|     // because they don't! see bug 696636
 | |
|     *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
 | |
|     aFailureId = "FEATURE_FAILURE_OPENGL_1";
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // Blocklist software GL implementations from using layers acceleration.
 | |
|   // On the test infrastructure, we'll force-enable layers acceleration.
 | |
|   if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS && !mIsAccelerated &&
 | |
|       !PR_GetEnv("MOZ_LAYERS_ALLOW_SOFTWARE_GL")) {
 | |
|     *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
 | |
|     aFailureId = "FEATURE_FAILURE_SOFTWARE_GL";
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   return GfxInfoBase::GetFeatureStatusImpl(
 | |
|       aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetD2DEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetDWriteEnabled(bool* aEnabled) { return NS_ERROR_FAILURE; }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetDWriteVersion(nsAString& aDwriteVersion) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP GfxInfo::GetHasBattery(bool* aHasBattery) {
 | |
|   return NS_ERROR_NOT_IMPLEMENTED;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetEmbeddedInFirefoxReality(bool* aEmbeddedInFirefoxReality) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetCleartypeParameters(nsAString& aCleartypeParams) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) {
 | |
|   GetData();
 | |
|   if (mIsWayland) {
 | |
|     aWindowProtocol = GfxDriverInfo::GetWindowProtocol(WindowProtocol::Wayland);
 | |
|   } else if (mIsXWayland) {
 | |
|     aWindowProtocol =
 | |
|         GfxDriverInfo::GetWindowProtocol(WindowProtocol::XWayland);
 | |
|   } else {
 | |
|     aWindowProtocol = GfxDriverInfo::GetWindowProtocol(WindowProtocol::X11);
 | |
|   }
 | |
|   Telemetry::ScalarSet(Telemetry::ScalarID::GFX_LINUX_WINDOW_PROTOCOL,
 | |
|                        aWindowProtocol);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetDesktopEnvironment(nsAString& aDesktopEnvironment) {
 | |
|   GetData();
 | |
|   AppendASCIItoUTF16(mDesktopEnvironment, aDesktopEnvironment);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetTestType(nsAString& aTestType) {
 | |
|   GetData();
 | |
|   AppendASCIItoUTF16(mTestType, aTestType);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
 | |
|   GetData();
 | |
|   AppendASCIItoUTF16(mAdapterDescription, aAdapterDescription);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDescription2(nsAString& aAdapterDescription) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterRAM(uint32_t* aAdapterRAM) {
 | |
|   GetData();
 | |
|   *aAdapterRAM = mAdapterRAM;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterRAM2(uint32_t* aAdapterRAM) { return NS_ERROR_FAILURE; }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDriver(nsAString& aAdapterDriver) {
 | |
|   aAdapterDriver.Truncate();
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDriver2(nsAString& aAdapterDriver) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDriverVendor(nsAString& aAdapterDriverVendor) {
 | |
|   GetData();
 | |
|   CopyASCIItoUTF16(mDriverVendor, aAdapterDriverVendor);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDriverVendor2(nsAString& aAdapterDriverVendor) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDriverVersion(nsAString& aAdapterDriverVersion) {
 | |
|   GetData();
 | |
|   CopyASCIItoUTF16(mDriverVersion, aAdapterDriverVersion);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDriverVersion2(nsAString& aAdapterDriverVersion) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDriverDate(nsAString& aAdapterDriverDate) {
 | |
|   aAdapterDriverDate.Truncate();
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDriverDate2(nsAString& aAdapterDriverDate) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterVendorID(nsAString& aAdapterVendorID) {
 | |
|   GetData();
 | |
|   CopyUTF8toUTF16(mVendorId, aAdapterVendorID);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) {
 | |
|   GetData();
 | |
|   CopyUTF8toUTF16(mSecondaryVendorId, aAdapterVendorID);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDeviceID(nsAString& aAdapterDeviceID) {
 | |
|   GetData();
 | |
|   CopyUTF8toUTF16(mDeviceId, aAdapterDeviceID);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) {
 | |
|   GetData();
 | |
|   CopyUTF8toUTF16(mSecondaryDeviceId, aAdapterDeviceID);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterSubsysID(nsAString& aAdapterSubsysID) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetAdapterSubsysID2(nsAString& aAdapterSubsysID) {
 | |
|   return NS_ERROR_FAILURE;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetDisplayInfo(nsTArray<nsString>& aDisplayInfo) {
 | |
|   GetData();
 | |
| 
 | |
|   for (auto screenInfo : mScreenInfo) {
 | |
|     nsString infoString;
 | |
|     infoString.AppendPrintf("%dx%d %s", screenInfo.mWidth, screenInfo.mHeight,
 | |
|                             screenInfo.mIsDefault ? "default" : "");
 | |
|     aDisplayInfo.AppendElement(infoString);
 | |
|   }
 | |
| 
 | |
|   return aDisplayInfo.IsEmpty() ? NS_ERROR_FAILURE : NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetDisplayWidth(nsTArray<uint32_t>& aDisplayWidth) {
 | |
|   for (auto screenInfo : mScreenInfo) {
 | |
|     aDisplayWidth.AppendElement((uint32_t)screenInfo.mWidth);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetDisplayHeight(nsTArray<uint32_t>& aDisplayHeight) {
 | |
|   for (auto screenInfo : mScreenInfo) {
 | |
|     aDisplayHeight.AppendElement((uint32_t)screenInfo.mHeight);
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) {
 | |
|   // This is never the case, as the active GPU should be the primary GPU.
 | |
|   *aIsGPU2Active = false;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP
 | |
| GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
 | |
|   GetData();
 | |
|   aDrmRenderDevice.Assign(mDrmRenderDevice);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| #ifdef DEBUG
 | |
| 
 | |
| // Implement nsIGfxInfoDebug
 | |
| // We don't support spoofing anything on Linux
 | |
| 
 | |
| NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString& aVendorID) {
 | |
|   GetData();
 | |
|   CopyUTF16toUTF8(aVendorID, mVendorId);
 | |
|   mIsAccelerated = true;
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString& aDeviceID) {
 | |
|   GetData();
 | |
|   CopyUTF16toUTF8(aDeviceID, mDeviceId);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString& aDriverVersion) {
 | |
|   GetData();
 | |
|   CopyUTF16toUTF8(aDriverVersion, mDriverVersion);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion) {
 | |
|   // We don't support OS versioning on Linux. There's just "Linux".
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| NS_IMETHODIMP GfxInfo::FireTestProcess() {
 | |
|   // If the pid is zero, then we have never run the test process to query for
 | |
|   // driver information. This would normally be run on startup, but we need to
 | |
|   // manually invoke it for XPC shell tests.
 | |
|   if (glxtest_pid == 0) {
 | |
|     fire_glxtest_process();
 | |
|   }
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| }  // namespace mozilla::widget
 |