diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /widget/GfxInfoX11.cpp | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'widget/GfxInfoX11.cpp')
-rw-r--r-- | widget/GfxInfoX11.cpp | 1153 |
1 files changed, 1153 insertions, 0 deletions
diff --git a/widget/GfxInfoX11.cpp b/widget/GfxInfoX11.cpp new file mode 100644 index 0000000000..6443e1b51c --- /dev/null +++ b/widget/GfxInfoX11.cpp @@ -0,0 +1,1153 @@ +/* -*- 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 <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> +#include <sys/utsname.h> +#include <string> +#include <cctype> +#include "nsCRTGlue.h" +#include "nsExceptionHandler.h" +#include "nsUnicharUtils.h" +#include "prenv.h" +#include "nsPrintfCString.h" +#include "nsWhitespaceTokenizer.h" +#include "mozilla/Telemetry.h" +#include "mozilla/gfx/Logging.h" + +#include "GfxInfoX11.h" + +#include <gdk/gdkx.h> +#ifdef MOZ_WAYLAND +# include "mozilla/widget/nsWaylandDisplay.h" +# include "mozilla/widget/DMABufLibWrapper.h" +#endif + +#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; + mIsWaylandDRM = 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::IsWaylandDRM, + mIsWaylandDRM); + 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; + + // 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, "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); + + // 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") || + !mIsAccelerated) { + // Fallback to reporting swrast if GLX_MESA_query_renderer tells us + // we're using an unaccelerated context. + CopyUTF16toUTF8(GfxDriverInfo::GetDriverVendor(DriverVendor::MesaSWRast), + mDriverVendor); + mIsAccelerated = false; + } 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; + } + } 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.Length() == 1) { + mVendorId = pciVendors[0]; + } else if (pciVendors.IsEmpty()) { + gfxCriticalNote << "No GPUs detected via PCI"; + } else { + gfxCriticalNote + << "More than 1 GPU detected via PCI, cannot deduce vendor"; + } + } + + // 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 { + 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); +#ifdef MOZ_WAYLAND + mIsWayland = gdk_display_get_default() && + !GDK_IS_X11_DISPLAY(gdk_display_get_default()); + if (mIsWayland) { + mIsWaylandDRM = GetDMABufDevice()->IsDMABufVAAPIEnabled() || + GetDMABufDevice()->IsDMABufWebGLEnabled() || + GetDMABufDevice()->IsDMABufTexturesEnabled(); + } +#endif + + // 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. + const char* windowEnv = getenv("XDG_SESSION_TYPE"); + mIsXWayland = windowEnv && strcmp(windowEnv, "wayland") == 0; + + // 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) { + 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 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 + + // 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(18, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 18.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::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 Nvidia devices not using Mesa for now. + 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_COMPARISON_IGNORED, + V(0, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_NO_LINUX_NVIDIA", ""); + + // 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(18, 0, 0, 0), "FEATURE_FAILURE_WEBRENDER_OLD_MESA", "Mesa 18.0.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", ""); + + //////////////////////////////////// + // FEATURE_WEBRENDER - ALLOWLIST + + // Intel Mesa baseline, chosen arbitrarily. + APPEND_TO_DRIVER_BLOCKLIST_EXT( + OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, + DesktopEnvironment::GNOME, WindowProtocol::X11, DriverVendor::MesaAll, + DeviceFamily::IntelRolloutWebRender, nsIGfxInfo::FEATURE_WEBRENDER, + nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_GREATER_THAN_OR_EQUAL, + V(18, 0, 0, 0), "FEATURE_ROLLOUT_INTEL_GNOME_X11_MESA", + "Mesa 18.0.0.0"); + + APPEND_TO_DRIVER_BLOCKLIST_EXT( + OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, + DesktopEnvironment::GNOME, WindowProtocol::Wayland, + DriverVendor::MesaAll, DeviceFamily::IntelRolloutWebRender, + nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_ALLOW_ALWAYS, + DRIVER_GREATER_THAN_OR_EQUAL, V(18, 0, 0, 0), + "FEATURE_ROLLOUT_INTEL_GNOME_WAYLAND_MESA", "Mesa 18.0.0.0"); + + // ATI Mesa baseline, chosen arbitrarily. + APPEND_TO_DRIVER_BLOCKLIST_EXT( + OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, + DesktopEnvironment::GNOME, WindowProtocol::X11, DriverVendor::MesaAll, + DeviceFamily::AtiRolloutWebRender, nsIGfxInfo::FEATURE_WEBRENDER, + nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_GREATER_THAN_OR_EQUAL, + V(18, 0, 0, 0), "FEATURE_ROLLOUT_ATI_GNOME_X11_MESA", "Mesa 18.0.0.0"); + + APPEND_TO_DRIVER_BLOCKLIST_EXT( + OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, + DesktopEnvironment::GNOME, WindowProtocol::Wayland, + DriverVendor::MesaAll, DeviceFamily::AtiRolloutWebRender, + nsIGfxInfo::FEATURE_WEBRENDER, nsIGfxInfo::FEATURE_ALLOW_ALWAYS, + DRIVER_GREATER_THAN_OR_EQUAL, V(18, 0, 0, 0), + "FEATURE_ROLLOUT_ATI_GNOME_WAYLAND_MESA", "Mesa 18.0.0.0"); + +#ifdef EARLY_BETA_OR_EARLIER + // 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(18, 0, 0, 0), "FEATURE_ROLLOUT_EARLY_BETA_INTEL_MESA", + "Mesa 18.0.0.0"); + + // 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(18, 0, 0, 0), "FEATURE_ROLLOUT_EARLY_BETA_ATI_MESA", "Mesa 18.0.0.0"); +#endif + +#ifdef NIGHTLY_BUILD + // 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_QUALIFIED, DRIVER_GREATER_THAN_OR_EQUAL, + V(18, 0, 0, 0), "FEATURE_ROLLOUT_NIGHTLY_INTEL_MESA", "Mesa 18.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_NIGHTLY_NVIDIA_MESA", "Mesa 18.2.0.0"); + + // 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_QUALIFIED, DRIVER_GREATER_THAN_OR_EQUAL, + V(18, 0, 0, 0), "FEATURE_ROLLOUT_NIGHTLY_ATI_MESA", "Mesa 18.0.0.0"); +#endif + + //////////////////////////////////// + // FEATURE_WEBRENDER_SOFTWARE - ALLOWLIST +#ifdef EARLY_BETA_OR_EARLIER +# if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \ + defined(__i386) || defined(__amd64__) + APPEND_TO_DRIVER_BLOCKLIST_EXT( + OperatingSystem::Linux, ScreenSizeStatus::SmallAndMedium, + BatteryStatus::All, DesktopEnvironment::All, WindowProtocol::All, + DriverVendor::NonMesaAll, DeviceFamily::All, + nsIGfxInfo::FEATURE_WEBRENDER_SOFTWARE, + nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_COMPARISON_IGNORED, + V(0, 0, 0, 0), "FEATURE_ROLLOUT_NIGHTLY_SOFTWARE_WR_NON_MESA_S_M_SCRN", + ""); + + APPEND_TO_DRIVER_BLOCKLIST_EXT( + OperatingSystem::Linux, ScreenSizeStatus::SmallAndMedium, + BatteryStatus::All, DesktopEnvironment::All, WindowProtocol::All, + DriverVendor::HardwareMesaAll, DeviceFamily::All, + nsIGfxInfo::FEATURE_WEBRENDER_SOFTWARE, + nsIGfxInfo::FEATURE_ALLOW_ALWAYS, DRIVER_COMPARISON_IGNORED, + V(0, 0, 0, 0), "FEATURE_ROLLOUT_NIGHTLY_SOFTWARE_WR_HW_MESA_S_M_SCRN", + ""); +# endif +#endif + + //////////////////////////////////// + + 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) { + if (mIsWaylandDRM) { + aWindowProtocol = + GfxDriverInfo::GetWindowProtocol(WindowProtocol::WaylandDRM); + } else { + 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::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 |