зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1588904 - [Linux/EGL] Use correct rendering device in multi-GPU setup, r=stransky,emilio,jgilbert
Fetch the DRM device in the EGL version of glxtest, set it in gfxInfo and pass it to gfxVars. Finally, use it in nsDMABufDevice::Configure(). While on it, also clean up EGL typedefs and defines a bit to match how it's done for GLX. Inspired by and copied from wlroots and Xwayland. Thanks to emersion! Differential Revision: https://phabricator.services.mozilla.com/D98108
This commit is contained in:
Родитель
d4d28b7263
Коммит
2fd87154fc
|
@ -73,7 +73,8 @@ class gfxVarReceiver;
|
||||||
_(FxREmbedded, bool, false) \
|
_(FxREmbedded, bool, false) \
|
||||||
_(UseAHardwareBufferContent, bool, false) \
|
_(UseAHardwareBufferContent, bool, false) \
|
||||||
_(UseAHardwareBufferSharedSurface, bool, false) \
|
_(UseAHardwareBufferSharedSurface, bool, false) \
|
||||||
_(UseEGL, bool, false)
|
_(UseEGL, bool, false) \
|
||||||
|
_(DrmRenderDevice, nsCString, nsCString())
|
||||||
|
|
||||||
/* Add new entries above this line. */
|
/* Add new entries above this line. */
|
||||||
|
|
||||||
|
|
|
@ -223,6 +223,9 @@ class MockGfxInfo final : public nsIGfxInfo {
|
||||||
NS_IMETHOD GetDisplayHeight(nsTArray<uint32_t>& aDisplayHeight) override {
|
NS_IMETHOD GetDisplayHeight(nsTArray<uint32_t>& aDisplayHeight) override {
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
NS_IMETHOD GetDrmRenderDevice(nsACString& aDrmRenderDevice) override {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
NS_IMETHOD ControlGPUProcessForXPCShell(bool aEnable,
|
NS_IMETHOD ControlGPUProcessForXPCShell(bool aEnable,
|
||||||
bool* _retval) override {
|
bool* _retval) override {
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
|
|
@ -102,6 +102,11 @@ gfxPlatformGtk::gfxPlatformGtk() {
|
||||||
#endif
|
#endif
|
||||||
if (IsWaylandDisplay() || useEGLOnX11) {
|
if (IsWaylandDisplay() || useEGLOnX11) {
|
||||||
gfxVars::SetUseEGL(true);
|
gfxVars::SetUseEGL(true);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||||
|
nsAutoCString drmRenderDevice;
|
||||||
|
gfxInfo->GetDrmRenderDevice(drmRenderDevice);
|
||||||
|
gfxVars::SetDrmRenderDevice(drmRenderDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,23 +84,62 @@ typedef uint32_t GLenum;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// stuff from egl.h
|
// stuff from egl.h
|
||||||
|
typedef intptr_t EGLAttrib;
|
||||||
|
typedef int EGLBoolean;
|
||||||
|
typedef void* EGLConfig;
|
||||||
|
typedef void* EGLContext;
|
||||||
|
typedef void* EGLDeviceEXT;
|
||||||
|
typedef void* EGLDisplay;
|
||||||
|
typedef int EGLint;
|
||||||
|
typedef void* EGLNativeDisplayType;
|
||||||
|
typedef void* EGLSurface;
|
||||||
|
typedef void* (*PFNEGLGETPROCADDRESS)(const char*);
|
||||||
|
|
||||||
|
#define EGL_NO_CONTEXT nullptr
|
||||||
|
#define EGL_FALSE 0
|
||||||
|
#define EGL_TRUE 1
|
||||||
#define EGL_BLUE_SIZE 0x3022
|
#define EGL_BLUE_SIZE 0x3022
|
||||||
#define EGL_GREEN_SIZE 0x3023
|
#define EGL_GREEN_SIZE 0x3023
|
||||||
#define EGL_RED_SIZE 0x3024
|
#define EGL_RED_SIZE 0x3024
|
||||||
#define EGL_NONE 0x3038
|
#define EGL_NONE 0x3038
|
||||||
#define EGL_VENDOR 0x3053
|
#define EGL_VENDOR 0x3053
|
||||||
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
|
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
|
||||||
#define EGL_NO_CONTEXT nullptr
|
#define EGL_DEVICE_EXT 0x322C
|
||||||
|
#define EGL_DRM_DEVICE_FILE_EXT 0x3233
|
||||||
|
|
||||||
|
// stuff from xf86drm.h
|
||||||
|
#define DRM_NODE_RENDER 2
|
||||||
|
#define DRM_NODE_MAX 3
|
||||||
|
|
||||||
|
typedef struct _drmDevice {
|
||||||
|
char** nodes;
|
||||||
|
int available_nodes;
|
||||||
|
int bustype;
|
||||||
|
union {
|
||||||
|
void* pci;
|
||||||
|
void* usb;
|
||||||
|
void* platform;
|
||||||
|
void* host1x;
|
||||||
|
} businfo;
|
||||||
|
union {
|
||||||
|
void* pci;
|
||||||
|
void* usb;
|
||||||
|
void* platform;
|
||||||
|
void* host1x;
|
||||||
|
} deviceinfo;
|
||||||
|
} drmDevice, *drmDevicePtr;
|
||||||
|
|
||||||
// Open libGL and load needed symbols
|
// Open libGL and load needed symbols
|
||||||
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
# define LIBGL_FILENAME "libGL.so"
|
# define LIBGL_FILENAME "libGL.so"
|
||||||
# define LIBGLES_FILENAME "libGLESv2.so"
|
# define LIBGLES_FILENAME "libGLESv2.so"
|
||||||
# define LIBEGL_FILENAME "libEGL.so"
|
# define LIBEGL_FILENAME "libEGL.so"
|
||||||
|
# define LIBDRM_FILENAME "libdrm.so"
|
||||||
#else
|
#else
|
||||||
# define LIBGL_FILENAME "libGL.so.1"
|
# define LIBGL_FILENAME "libGL.so.1"
|
||||||
# define LIBGLES_FILENAME "libGLESv2.so.2"
|
# define LIBGLES_FILENAME "libGLESv2.so.2"
|
||||||
# define LIBEGL_FILENAME "libEGL.so.1"
|
# define LIBEGL_FILENAME "libEGL.so.1"
|
||||||
|
# define LIBDRM_FILENAME "libdrm.so.2"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EXIT_FAILURE_BUFFER_TOO_SMALL 2
|
#define EXIT_FAILURE_BUFFER_TOO_SMALL 2
|
||||||
|
@ -282,18 +321,91 @@ static void get_pci_status() {
|
||||||
dlclose(libpci);
|
dlclose(libpci);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void* EGLNativeDisplayType;
|
#ifdef MOZ_WAYLAND
|
||||||
typedef void* EGLDisplay;
|
static bool device_has_name(const drmDevice* device, const char* name) {
|
||||||
typedef int EGLBoolean;
|
for (size_t i = 0; i < DRM_NODE_MAX; i++) {
|
||||||
typedef int EGLint;
|
if (!(device->available_nodes & (1 << i))) {
|
||||||
typedef void* (*PFNEGLGETPROCADDRESS)(const char*);
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(device->nodes[i], name) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* get_render_name(const char* name) {
|
||||||
|
void* libdrm = dlopen(LIBDRM_FILENAME, RTLD_LAZY);
|
||||||
|
if (!libdrm) {
|
||||||
|
record_warning("Failed to open libdrm");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef int (*DRMGETDEVICES2)(uint32_t, drmDevicePtr*, int);
|
||||||
|
DRMGETDEVICES2 drmGetDevices2 =
|
||||||
|
cast<DRMGETDEVICES2>(dlsym(libdrm, "drmGetDevices2"));
|
||||||
|
|
||||||
|
typedef void (*DRMFREEDEVICE)(drmDevicePtr*);
|
||||||
|
DRMFREEDEVICE drmFreeDevice =
|
||||||
|
cast<DRMFREEDEVICE>(dlsym(libdrm, "drmFreeDevice"));
|
||||||
|
|
||||||
|
if (!drmGetDevices2 || !drmFreeDevice) {
|
||||||
|
record_warning(
|
||||||
|
"libdrm missing methods for drmGetDevices2 or drmFreeDevice");
|
||||||
|
dlclose(libdrm);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flags = 0;
|
||||||
|
int devices_len = drmGetDevices2(flags, nullptr, 0);
|
||||||
|
if (devices_len < 0) {
|
||||||
|
record_warning("drmGetDevices2 failed");
|
||||||
|
dlclose(libdrm);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
drmDevice** devices = (drmDevice**)calloc(devices_len, sizeof(drmDevice*));
|
||||||
|
if (!devices) {
|
||||||
|
record_warning("Allocation error");
|
||||||
|
dlclose(libdrm);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
devices_len = drmGetDevices2(flags, devices, devices_len);
|
||||||
|
if (devices_len < 0) {
|
||||||
|
free(devices);
|
||||||
|
record_warning("drmGetDevices2 failed");
|
||||||
|
dlclose(libdrm);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const drmDevice* match = nullptr;
|
||||||
|
for (int i = 0; i < devices_len; i++) {
|
||||||
|
if (device_has_name(devices[i], name)) {
|
||||||
|
match = devices[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* render_name = nullptr;
|
||||||
|
if (!match) {
|
||||||
|
record_warning("Cannot find DRM device");
|
||||||
|
} else if (!(match->available_nodes & (1 << DRM_NODE_RENDER))) {
|
||||||
|
record_warning("DRM device has no render node");
|
||||||
|
} else {
|
||||||
|
render_name = strdup(match->nodes[DRM_NODE_RENDER]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < devices_len; i++) {
|
||||||
|
drmFreeDevice(&devices[i]);
|
||||||
|
}
|
||||||
|
free(devices);
|
||||||
|
|
||||||
|
dlclose(libdrm);
|
||||||
|
return render_name;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void get_gles_status(EGLDisplay dpy,
|
static void get_gles_status(EGLDisplay dpy,
|
||||||
PFNEGLGETPROCADDRESS eglGetProcAddress) {
|
PFNEGLGETPROCADDRESS eglGetProcAddress) {
|
||||||
typedef void* EGLConfig;
|
|
||||||
typedef void* EGLContext;
|
|
||||||
typedef void* EGLSurface;
|
|
||||||
|
|
||||||
typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(
|
typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(
|
||||||
EGLDisplay dpy, EGLint const* attrib_list, EGLConfig* configs,
|
EGLDisplay dpy, EGLint const* attrib_list, EGLConfig* configs,
|
||||||
EGLint config_size, EGLint* num_config);
|
EGLint config_size, EGLint* num_config);
|
||||||
|
@ -317,6 +429,18 @@ static void get_gles_status(EGLDisplay dpy,
|
||||||
PFNEGLMAKECURRENTPROC eglMakeCurrent =
|
PFNEGLMAKECURRENTPROC eglMakeCurrent =
|
||||||
cast<PFNEGLMAKECURRENTPROC>(eglGetProcAddress("eglMakeCurrent"));
|
cast<PFNEGLMAKECURRENTPROC>(eglGetProcAddress("eglMakeCurrent"));
|
||||||
|
|
||||||
|
typedef const char* (*PFNEGLQUERYDEVICESTRINGEXTPROC)(EGLDeviceEXT device,
|
||||||
|
EGLint name);
|
||||||
|
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT =
|
||||||
|
cast<PFNEGLQUERYDEVICESTRINGEXTPROC>(
|
||||||
|
eglGetProcAddress("eglQueryDeviceStringEXT"));
|
||||||
|
|
||||||
|
typedef EGLBoolean (*PFNEGLQUERYDISPLAYATTRIBEXTPROC)(
|
||||||
|
EGLDisplay dpy, EGLint name, EGLAttrib * value);
|
||||||
|
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT =
|
||||||
|
cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(
|
||||||
|
eglGetProcAddress("eglQueryDisplayAttribEXT"));
|
||||||
|
|
||||||
if (!eglChooseConfig || !eglCreateContext || !eglCreatePbufferSurface ||
|
if (!eglChooseConfig || !eglCreateContext || !eglCreatePbufferSurface ||
|
||||||
!eglMakeCurrent) {
|
!eglMakeCurrent) {
|
||||||
record_error("libEGL missing methods for GLES test");
|
record_error("libEGL missing methods for GLES test");
|
||||||
|
@ -370,6 +494,28 @@ static void get_gles_status(EGLDisplay dpy,
|
||||||
record_error("libGLESv2 glGetString returned null");
|
record_error("libGLESv2 glGetString returned null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (eglQueryDeviceStringEXT) {
|
||||||
|
EGLDeviceEXT device = nullptr;
|
||||||
|
|
||||||
|
if (eglQueryDisplayAttribEXT(dpy, EGL_DEVICE_EXT, (EGLAttrib*)&device) ==
|
||||||
|
EGL_TRUE) {
|
||||||
|
const char* deviceString =
|
||||||
|
eglQueryDeviceStringEXT(device, EGL_DRM_DEVICE_FILE_EXT);
|
||||||
|
if (deviceString) {
|
||||||
|
record_value("MESA_ACCELERATED\nTRUE\n");
|
||||||
|
|
||||||
|
#ifdef MOZ_WAYLAND
|
||||||
|
char* renderDeviceName = get_render_name(deviceString);
|
||||||
|
if (renderDeviceName) {
|
||||||
|
record_value("DRM_RENDERDEVICE\n%s\n", renderDeviceName);
|
||||||
|
} else {
|
||||||
|
record_warning("Can't find render node name for DRM device");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (libgl) {
|
if (libgl) {
|
||||||
dlclose(libgl);
|
dlclose(libgl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,6 +167,8 @@ void GfxInfo::GetData() {
|
||||||
nsCString screenInfo;
|
nsCString screenInfo;
|
||||||
nsCString adapterRam;
|
nsCString adapterRam;
|
||||||
|
|
||||||
|
nsCString drmRenderDevice;
|
||||||
|
|
||||||
AutoTArray<nsCString, 2> pciVendors;
|
AutoTArray<nsCString, 2> pciVendors;
|
||||||
AutoTArray<nsCString, 2> pciDevices;
|
AutoTArray<nsCString, 2> pciDevices;
|
||||||
|
|
||||||
|
@ -207,6 +209,8 @@ void GfxInfo::GetData() {
|
||||||
stringToFill = pciVendors.AppendElement();
|
stringToFill = pciVendors.AppendElement();
|
||||||
} else if (!strcmp(line, "PCI_DEVICE_ID")) {
|
} else if (!strcmp(line, "PCI_DEVICE_ID")) {
|
||||||
stringToFill = pciDevices.AppendElement();
|
stringToFill = pciDevices.AppendElement();
|
||||||
|
} else if (!strcmp(line, "DRM_RENDERDEVICE")) {
|
||||||
|
stringToFill = &drmRenderDevice;
|
||||||
} else if (!strcmp(line, "WARNING")) {
|
} else if (!strcmp(line, "WARNING")) {
|
||||||
logString = true;
|
logString = true;
|
||||||
} else if (!strcmp(line, "ERROR")) {
|
} else if (!strcmp(line, "ERROR")) {
|
||||||
|
@ -265,6 +269,8 @@ void GfxInfo::GetData() {
|
||||||
NS_WARNING("Failed to parse GL version!");
|
NS_WARNING("Failed to parse GL version!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDrmRenderDevice = std::move(drmRenderDevice);
|
||||||
|
|
||||||
// Mesa always exposes itself in the GL_VERSION string, but not always the
|
// Mesa always exposes itself in the GL_VERSION string, but not always the
|
||||||
// GL_VENDOR string.
|
// GL_VENDOR string.
|
||||||
mIsMesa = glVersion.Find("Mesa") != -1;
|
mIsMesa = glVersion.Find("Mesa") != -1;
|
||||||
|
@ -1096,6 +1102,13 @@ GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
GfxInfo::GetDrmRenderDevice(nsACString& aDrmRenderDevice) {
|
||||||
|
GetData();
|
||||||
|
aDrmRenderDevice.Assign(mDrmRenderDevice);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
// Implement nsIGfxInfoDebug
|
// Implement nsIGfxInfoDebug
|
||||||
|
|
|
@ -50,6 +50,7 @@ class GfxInfo final : public GfxInfoBase {
|
||||||
NS_IMETHOD GetDisplayInfo(nsTArray<nsString>& aDisplayInfo) override;
|
NS_IMETHOD GetDisplayInfo(nsTArray<nsString>& aDisplayInfo) override;
|
||||||
NS_IMETHOD GetDisplayWidth(nsTArray<uint32_t>& aDisplayWidth) override;
|
NS_IMETHOD GetDisplayWidth(nsTArray<uint32_t>& aDisplayWidth) override;
|
||||||
NS_IMETHOD GetDisplayHeight(nsTArray<uint32_t>& aDisplayHeight) override;
|
NS_IMETHOD GetDisplayHeight(nsTArray<uint32_t>& aDisplayHeight) override;
|
||||||
|
NS_IMETHOD GetDrmRenderDevice(nsACString& aDrmRenderDevice) override;
|
||||||
using GfxInfoBase::GetFeatureStatus;
|
using GfxInfoBase::GetFeatureStatus;
|
||||||
using GfxInfoBase::GetFeatureSuggestedDriverVersion;
|
using GfxInfoBase::GetFeatureSuggestedDriverVersion;
|
||||||
|
|
||||||
|
@ -92,6 +93,8 @@ class GfxInfo final : public GfxInfoBase {
|
||||||
nsCString mSecondaryVendorId;
|
nsCString mSecondaryVendorId;
|
||||||
nsCString mSecondaryDeviceId;
|
nsCString mSecondaryDeviceId;
|
||||||
|
|
||||||
|
nsCString mDrmRenderDevice;
|
||||||
|
|
||||||
struct ScreenInfo {
|
struct ScreenInfo {
|
||||||
uint32_t mWidth;
|
uint32_t mWidth;
|
||||||
uint32_t mHeight;
|
uint32_t mHeight;
|
||||||
|
|
|
@ -201,21 +201,24 @@ bool nsDMABufDevice::Configure() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - Better DRM device detection/configuration.
|
nsAutoCString drm_render_node(getenv("MOZ_WAYLAND_DRM_DEVICE"));
|
||||||
const char* drm_render_node = getenv("MOZ_WAYLAND_DRM_DEVICE");
|
if (drm_render_node.IsEmpty()) {
|
||||||
if (!drm_render_node) {
|
drm_render_node.Assign(gfx::gfxVars::DrmRenderDevice());
|
||||||
drm_render_node = "/dev/dri/renderD128";
|
if (drm_render_node.IsEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mGbmFd = open(drm_render_node, O_RDWR);
|
mGbmFd = open(drm_render_node.get(), O_RDWR);
|
||||||
if (mGbmFd < 0) {
|
if (mGbmFd < 0) {
|
||||||
LOGDMABUF(("Failed to open drm render node %s\n", drm_render_node));
|
LOGDMABUF(("Failed to open drm render node %s\n", drm_render_node.get()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mGbmDevice = nsGbmLib::CreateDevice(mGbmFd);
|
mGbmDevice = nsGbmLib::CreateDevice(mGbmFd);
|
||||||
if (mGbmDevice == nullptr) {
|
if (!mGbmDevice) {
|
||||||
LOGDMABUF(("Failed to create drm render device %s\n", drm_render_node));
|
LOGDMABUF(
|
||||||
|
("Failed to create drm render device %s\n", drm_render_node.get()));
|
||||||
close(mGbmFd);
|
close(mGbmFd);
|
||||||
mGbmFd = -1;
|
mGbmFd = -1;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -77,6 +77,8 @@ interface nsIGfxInfo : nsISupports
|
||||||
|
|
||||||
readonly attribute boolean isGPU2Active;
|
readonly attribute boolean isGPU2Active;
|
||||||
|
|
||||||
|
readonly attribute ACString drmRenderDevice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about display devices
|
* Information about display devices
|
||||||
*/
|
*/
|
||||||
|
|
Загрузка…
Ссылка в новой задаче