mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1680512 - Prefer EGL for glxtest detection and fallback to GLX if unavailable. r=rmader
As we make the transition to using EGL over GLX, we will need our detection code to be sufficient without EGL to determine the device in use. This patch makes us always use the EGL testing code over the GLX testing code, regardless of the pref/envvar setting. At the very least, we need to know the vendor ID of the device in use. We can determine this if there is only one GPU on the PCI list, if we get a driver name from Mesa, or if it is a proprietary driver (i.e. NVIDIA) which includes its name in the vendor ID. If we know the vendor ID, we can usually derive the device ID from the PCI list. We now also track which path glxtest took. If we successfully did the test via EGL, then we will allow the pref/envvar to use EGL instead of GLX. If the test reverted to GLX, then it will use GLX regardless of the pref/envvar. This is necessary because we need to know if the libraries are available or not -- some systems may be missing one or the other. Differential Revision: https://phabricator.services.mozilla.com/D102933
This commit is contained in:
parent
48c01f0a8b
commit
cb82d29e76
@ -158,6 +158,9 @@ class MockGfxInfo final : public nsIGfxInfo {
|
||||
NS_IMETHOD GetDesktopEnvironment(nsAString& aDesktopEnvironment) override {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHOD GetTestType(nsAString& aTestType) override {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHOD GetAdapterDescription(nsAString& aAdapterDescription) override {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_gfx.h"
|
||||
#include "mozilla/StaticPrefs_layers.h"
|
||||
#include "nsAppRunner.h"
|
||||
#include "nsIGfxInfo.h"
|
||||
@ -80,6 +81,15 @@ static void screen_resolution_changed(GdkScreen* aScreen, GParamSpec* aPspec,
|
||||
sDPI = 0;
|
||||
}
|
||||
|
||||
#if defined(MOZ_X11)
|
||||
// TODO(aosmond): The envvar is deprecated. We should remove it once EGL is the
|
||||
// default in release.
|
||||
static bool IsX11EGLEnvvarEnabled() {
|
||||
const char* eglPref = PR_GetEnv("MOZ_X11_EGL");
|
||||
return (eglPref && *eglPref);
|
||||
}
|
||||
#endif
|
||||
|
||||
gfxPlatformGtk::gfxPlatformGtk() {
|
||||
if (!gfxPlatform::IsHeadless()) {
|
||||
gtk_init(nullptr, nullptr);
|
||||
@ -98,7 +108,17 @@ gfxPlatformGtk::gfxPlatformGtk() {
|
||||
|
||||
bool useEGLOnX11 = false;
|
||||
#ifdef MOZ_X11
|
||||
useEGLOnX11 = IsX11EGLEnabled();
|
||||
useEGLOnX11 =
|
||||
StaticPrefs::gfx_prefer_x11_egl_AtStartup() || IsX11EGLEnvvarEnabled();
|
||||
if (useEGLOnX11) {
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
nsAutoString testType;
|
||||
gfxInfo->GetTestType(testType);
|
||||
// We can only use X11/EGL if we actually found the EGL library and
|
||||
// successfully use it to determine system information in glxtest.
|
||||
useEGLOnX11 = testType == u"EGL";
|
||||
}
|
||||
|
||||
#endif
|
||||
if (IsWaylandDisplay() || useEGLOnX11) {
|
||||
gfxVars::SetUseEGL(true);
|
||||
|
@ -4447,6 +4447,12 @@
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
# Prefer EGL over GLX if available.
|
||||
- name: gfx.prefer-x11-egl
|
||||
type: bool
|
||||
value: false
|
||||
mirror: once
|
||||
|
||||
- name: gfx.testing.device-fail
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
|
@ -243,14 +243,14 @@ static void close_logging() {
|
||||
#define PCI_FILL_CLASS 0x0020
|
||||
#define PCI_BASE_CLASS_DISPLAY 0x03
|
||||
|
||||
static void get_pci_status() {
|
||||
static int get_pci_status() {
|
||||
void* libpci = dlopen("libpci.so.3", RTLD_LAZY);
|
||||
if (!libpci) {
|
||||
libpci = dlopen("libpci.so", RTLD_LAZY);
|
||||
}
|
||||
if (!libpci) {
|
||||
record_warning("libpci missing");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct pci_dev {
|
||||
@ -295,23 +295,25 @@ static void get_pci_status() {
|
||||
if (!pci_alloc || !pci_cleanup || !pci_scan_bus || !pci_fill_info) {
|
||||
dlclose(libpci);
|
||||
record_warning("libpci missing methods");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pci_access* pacc = pci_alloc();
|
||||
if (!pacc) {
|
||||
dlclose(libpci);
|
||||
record_warning("libpci alloc failed");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pci_init(pacc);
|
||||
pci_scan_bus(pacc);
|
||||
|
||||
int count = 0;
|
||||
for (pci_dev* dev = pacc->devices; dev; dev = dev->next) {
|
||||
pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS);
|
||||
if (dev->device_class >> 8 == PCI_BASE_CLASS_DISPLAY && dev->vendor_id &&
|
||||
dev->device_id) {
|
||||
++count;
|
||||
record_value("PCI_VENDOR_ID\n0x%04x\nPCI_DEVICE_ID\n0x%04x\n",
|
||||
dev->vendor_id, dev->device_id);
|
||||
}
|
||||
@ -319,6 +321,7 @@ static void get_pci_status() {
|
||||
|
||||
pci_cleanup(pacc);
|
||||
dlclose(libpci);
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WAYLAND
|
||||
@ -404,7 +407,7 @@ static char* get_render_name(const char* name) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static void get_gles_status(EGLDisplay dpy,
|
||||
static bool get_gles_status(EGLDisplay dpy,
|
||||
PFNEGLGETPROCADDRESS eglGetProcAddress) {
|
||||
typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(
|
||||
EGLDisplay dpy, EGLint const* attrib_list, EGLConfig* configs,
|
||||
@ -444,7 +447,7 @@ static void get_gles_status(EGLDisplay dpy,
|
||||
if (!eglChooseConfig || !eglCreateContext || !eglCreatePbufferSurface ||
|
||||
!eglMakeCurrent) {
|
||||
record_error("libEGL missing methods for GLES test");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef GLubyte* (*PFNGLGETSTRING)(GLenum);
|
||||
@ -460,8 +463,8 @@ static void get_gles_status(EGLDisplay dpy,
|
||||
if (!libgl) {
|
||||
libgl = dlopen(LIBGLES_FILENAME, RTLD_LAZY);
|
||||
if (!libgl) {
|
||||
record_error("Unable to load " LIBGL_FILENAME " or " LIBGLES_FILENAME);
|
||||
return;
|
||||
record_warning(LIBGL_FILENAME " and " LIBGLES_FILENAME " missing");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,7 +472,7 @@ static void get_gles_status(EGLDisplay dpy,
|
||||
if (!glGetString) {
|
||||
dlclose(libgl);
|
||||
record_error("libGL or libGLESv2 glGetString missing");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -519,13 +522,15 @@ static void get_gles_status(EGLDisplay dpy,
|
||||
if (libgl) {
|
||||
dlclose(libgl);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void get_egl_status(EGLNativeDisplayType native_dpy, bool gles_test) {
|
||||
static bool get_egl_status(EGLNativeDisplayType native_dpy, bool gles_test,
|
||||
bool require_driver) {
|
||||
void* libegl = dlopen(LIBEGL_FILENAME, RTLD_LAZY);
|
||||
if (!libegl) {
|
||||
record_warning("libEGL missing");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
PFNEGLGETPROCADDRESS eglGetProcAddress =
|
||||
@ -534,7 +539,7 @@ static void get_egl_status(EGLNativeDisplayType native_dpy, bool gles_test) {
|
||||
if (!eglGetProcAddress) {
|
||||
dlclose(libegl);
|
||||
record_error("no eglGetProcAddress");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef EGLDisplay (*PFNEGLGETDISPLAYPROC)(void* native_display);
|
||||
@ -553,25 +558,21 @@ static void get_egl_status(EGLNativeDisplayType native_dpy, bool gles_test) {
|
||||
if (!eglGetDisplay || !eglInitialize || !eglTerminate) {
|
||||
dlclose(libegl);
|
||||
record_error("libEGL missing methods");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLDisplay dpy = eglGetDisplay(native_dpy);
|
||||
if (!dpy) {
|
||||
dlclose(libegl);
|
||||
record_warning("libEGL no display");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLint major, minor;
|
||||
if (!eglInitialize(dpy, &major, &minor)) {
|
||||
dlclose(libegl);
|
||||
record_warning("libEGL initialize failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gles_test) {
|
||||
get_gles_status(dpy, eglGetProcAddress);
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef const char* (*PFNEGLGETDISPLAYDRIVERNAMEPROC)(EGLDisplay dpy);
|
||||
@ -579,14 +580,30 @@ static void get_egl_status(EGLNativeDisplayType native_dpy, bool gles_test) {
|
||||
cast<PFNEGLGETDISPLAYDRIVERNAMEPROC>(
|
||||
eglGetProcAddress("eglGetDisplayDriverName"));
|
||||
if (eglGetDisplayDriverName) {
|
||||
// TODO(aosmond): If the driver name is empty, we probably aren't using Mesa
|
||||
// and instead a proprietary GL, most likely NVIDIA's. The PCI device list
|
||||
// in combination with the vendor name is very likely sufficient to identify
|
||||
// the device.
|
||||
const char* driDriver = eglGetDisplayDriverName(dpy);
|
||||
if (driDriver) {
|
||||
record_value("DRI_DRIVER\n%s\n", driDriver);
|
||||
}
|
||||
} else if (require_driver) {
|
||||
record_warning("libEGL missing eglGetDisplayDriverName");
|
||||
eglTerminate(dpy);
|
||||
dlclose(libegl);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gles_test && !get_gles_status(dpy, eglGetProcAddress)) {
|
||||
eglTerminate(dpy);
|
||||
dlclose(libegl);
|
||||
return false;
|
||||
}
|
||||
|
||||
eglTerminate(dpy);
|
||||
dlclose(libegl);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_X11
|
||||
@ -786,8 +803,10 @@ static void get_glx_status(int* gotGlxInfo, int* gotDriDriver) {
|
||||
dlclose(libgl);
|
||||
}
|
||||
|
||||
static bool x11_egltest() {
|
||||
get_egl_status(nullptr, true);
|
||||
static bool x11_egltest(int pci_count) {
|
||||
if (!get_egl_status(nullptr, true, pci_count != 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Display* dpy = XOpenDisplay(nullptr);
|
||||
if (!dpy) {
|
||||
@ -798,6 +817,7 @@ static bool x11_egltest() {
|
||||
get_x11_screen_info(dpy);
|
||||
|
||||
XCloseDisplay(dpy);
|
||||
record_value("TEST_TYPE\nEGL\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -807,12 +827,14 @@ static void glxtest() {
|
||||
|
||||
get_glx_status(&gotGlxInfo, &gotDriDriver);
|
||||
if (!gotGlxInfo) {
|
||||
get_egl_status(nullptr, true);
|
||||
get_egl_status(nullptr, true, false);
|
||||
} else if (!gotDriDriver) {
|
||||
// If we failed to get the driver name from X, try via
|
||||
// EGL_MESA_query_driver. We are probably using Wayland.
|
||||
get_egl_status(nullptr, false);
|
||||
get_egl_status(nullptr, false, true);
|
||||
}
|
||||
|
||||
record_value("TEST_TYPE\nGLX\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1141,10 +1163,11 @@ static bool wayland_egltest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get_egl_status((EGLNativeDisplayType)dpy, true);
|
||||
get_egl_status((EGLNativeDisplayType)dpy, true, false);
|
||||
get_wayland_screen_info(dpy);
|
||||
|
||||
wl_display_disconnect(dpy);
|
||||
record_value("TEST_TYPE\nEGL\n");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@ -1159,7 +1182,7 @@ int childgltest() {
|
||||
glxtest_bufsize = bufsize;
|
||||
|
||||
// Get a list of all GPUs from the PCI bus.
|
||||
get_pci_status();
|
||||
int pci_count = get_pci_status();
|
||||
|
||||
bool result = false;
|
||||
#ifdef MOZ_WAYLAND
|
||||
@ -1169,8 +1192,8 @@ int childgltest() {
|
||||
#endif
|
||||
#ifdef MOZ_X11
|
||||
// TODO: --display command line argument is not properly handled
|
||||
if (!result && IsX11EGLEnabled()) {
|
||||
result = x11_egltest();
|
||||
if (!result) {
|
||||
result = x11_egltest(pci_count);
|
||||
}
|
||||
if (!result) {
|
||||
glxtest();
|
||||
|
@ -4124,13 +4124,6 @@ bool IsWaylandDisabled() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_X11)
|
||||
bool IsX11EGLEnabled() {
|
||||
const char* eglPref = PR_GetEnv("MOZ_X11_EGL");
|
||||
return (eglPref && *eglPref);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace mozilla::startup {
|
||||
Result<nsCOMPtr<nsIFile>, nsresult> GetIncompleteStartupFile(nsIFile* aProfLD) {
|
||||
nsCOMPtr<nsIFile> crashFile;
|
||||
|
@ -162,8 +162,5 @@ void setASanReporterPath(nsIFile* aDir);
|
||||
#ifdef MOZ_WAYLAND
|
||||
bool IsWaylandDisabled();
|
||||
#endif
|
||||
#ifdef MOZ_X11
|
||||
bool IsX11EGLEnabled();
|
||||
#endif
|
||||
|
||||
#endif // nsAppRunner_h__
|
||||
|
@ -157,6 +157,7 @@ void GfxInfo::GetData() {
|
||||
nsCString glRenderer;
|
||||
nsCString glVersion;
|
||||
nsCString textureFromPixmap;
|
||||
nsCString testType;
|
||||
|
||||
// Available if GLX_MESA_query_renderer is supported.
|
||||
nsCString mesaVendor;
|
||||
@ -211,6 +212,8 @@ void GfxInfo::GetData() {
|
||||
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")) {
|
||||
@ -270,6 +273,7 @@ void GfxInfo::GetData() {
|
||||
}
|
||||
|
||||
mDrmRenderDevice = std::move(drmRenderDevice);
|
||||
mTestType = std::move(testType);
|
||||
|
||||
// Mesa always exposes itself in the GL_VERSION string, but not always the
|
||||
// GL_VENDOR string.
|
||||
@ -582,7 +586,7 @@ void GfxInfo::GetData() {
|
||||
}
|
||||
}
|
||||
|
||||
if (error || errorLog) {
|
||||
if (error || errorLog || mTestType.IsEmpty()) {
|
||||
if (!mAdapterDescription.IsEmpty()) {
|
||||
mAdapterDescription.AppendLiteral(" (See failure log)");
|
||||
} else {
|
||||
@ -959,6 +963,13 @@ GfxInfo::GetDesktopEnvironment(nsAString& aDesktopEnvironment) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetTestType(nsAString& aTestType) {
|
||||
GetData();
|
||||
AppendASCIItoUTF16(mTestType, aTestType);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
|
||||
GetData();
|
||||
|
@ -27,6 +27,7 @@ class GfxInfo final : public GfxInfoBase {
|
||||
NS_IMETHOD GetCleartypeParameters(nsAString& aCleartypeParams) override;
|
||||
NS_IMETHOD GetWindowProtocol(nsAString& aWindowProtocol) override;
|
||||
NS_IMETHOD GetDesktopEnvironment(nsAString& aDesktopEnvironment) override;
|
||||
NS_IMETHOD GetTestType(nsAString& aTestType) override;
|
||||
NS_IMETHOD GetAdapterDescription(nsAString& aAdapterDescription) override;
|
||||
NS_IMETHOD GetAdapterDriver(nsAString& aAdapterDriver) override;
|
||||
NS_IMETHOD GetAdapterVendorID(nsAString& aAdapterVendorID) override;
|
||||
@ -89,6 +90,7 @@ class GfxInfo final : public GfxInfoBase {
|
||||
nsCString mOS;
|
||||
nsCString mOSRelease;
|
||||
nsAutoCStringN<16> mDesktopEnvironment;
|
||||
nsCString mTestType;
|
||||
|
||||
nsCString mSecondaryVendorId;
|
||||
nsCString mSecondaryDeviceId;
|
||||
|
@ -156,6 +156,9 @@ GfxInfo::GetDesktopEnvironment(nsAString& aDesktopEnvironment) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetTestType(nsAString& aTestType) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
void GfxInfo::EnsureInitialized() {
|
||||
if (mInitialized) return;
|
||||
|
||||
|
@ -36,6 +36,7 @@ class GfxInfo : public GfxInfoBase {
|
||||
NS_IMETHOD GetCleartypeParameters(nsAString& aCleartypeParams) override;
|
||||
NS_IMETHOD GetWindowProtocol(nsAString& aWindowProtocol) override;
|
||||
NS_IMETHOD GetDesktopEnvironment(nsAString& aDesktopEnvironment) override;
|
||||
NS_IMETHOD GetTestType(nsAString& aTestType) override;
|
||||
NS_IMETHOD GetAdapterDescription(nsAString& aAdapterDescription) override;
|
||||
NS_IMETHOD GetAdapterDriver(nsAString& aAdapterDriver) override;
|
||||
NS_IMETHOD GetAdapterVendorID(nsAString& aAdapterVendorID) override;
|
||||
|
@ -28,6 +28,7 @@ class GfxInfo : public GfxInfoBase {
|
||||
NS_IMETHOD GetHasBattery(bool* aHasBattery) override;
|
||||
NS_IMETHOD GetWindowProtocol(nsAString& aWindowProtocol) override;
|
||||
NS_IMETHOD GetDesktopEnvironment(nsAString& aDesktopEnvironment) override;
|
||||
NS_IMETHOD GetTestType(nsAString& aTestType) override;
|
||||
NS_IMETHOD GetCleartypeParameters(nsAString& aCleartypeParams) override;
|
||||
NS_IMETHOD GetAdapterDescription(nsAString& aAdapterDescription) override;
|
||||
NS_IMETHOD GetAdapterDriver(nsAString& aAdapterDriver) override;
|
||||
|
@ -210,6 +210,10 @@ GfxInfo::GetWindowProtocol(nsAString& aWindowProtocol) { return NS_ERROR_NOT_IMP
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetDesktopEnvironment(nsAString& aDesktopEnvironment) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
/* readonly attribute DOMString testType; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetTestType(nsAString& aTestType) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
/* readonly attribute DOMString adapterDescription; */
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetAdapterDescription(nsAString& aAdapterDescription) {
|
||||
|
@ -26,6 +26,7 @@ interface nsIGfxInfo : nsISupports
|
||||
*/
|
||||
readonly attribute AString windowProtocol;
|
||||
readonly attribute AString desktopEnvironment;
|
||||
readonly attribute AString testType;
|
||||
|
||||
/*
|
||||
* These are valid across all platforms.
|
||||
|
@ -169,6 +169,9 @@ GfxInfo::GetDesktopEnvironment(nsAString& aDesktopEnvironment) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GfxInfo::GetTestType(nsAString& aTestType) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
static nsresult GetKeyValue(const WCHAR* keyLocation, const WCHAR* keyName,
|
||||
uint32_t& destValue, int type) {
|
||||
MOZ_ASSERT(type == REG_DWORD || type == REG_QWORD);
|
||||
|
@ -30,6 +30,7 @@ class GfxInfo : public GfxInfoBase {
|
||||
NS_IMETHOD GetCleartypeParameters(nsAString& aCleartypeParams) override;
|
||||
NS_IMETHOD GetWindowProtocol(nsAString& aWindowProtocol) override;
|
||||
NS_IMETHOD GetDesktopEnvironment(nsAString& aDesktopEnvironment) override;
|
||||
NS_IMETHOD GetTestType(nsAString& aTestType) override;
|
||||
NS_IMETHOD GetAdapterDescription(nsAString& aAdapterDescription) override;
|
||||
NS_IMETHOD GetAdapterDriver(nsAString& aAdapterDriver) override;
|
||||
NS_IMETHOD GetAdapterVendorID(nsAString& aAdapterVendorID) override;
|
||||
|
Loading…
Reference in New Issue
Block a user