mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
Merge branch 'match-platform-device' into 'master'
Draft: render: open platform device render node See merge request wlroots/wlroots!4372
This commit is contained in:
commit
e6d9aa5d62
8 changed files with 133 additions and 130 deletions
87
render/egl.c
87
render/egl.c
|
|
@ -5,7 +5,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <gbm.h>
|
||||
#include <wlr/render/egl.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/util/region.h>
|
||||
|
|
@ -219,8 +218,6 @@ static struct wlr_egl *egl_create(void) {
|
|||
load_egl_proc(&egl->procs.eglGetPlatformDisplayEXT,
|
||||
"eglGetPlatformDisplayEXT");
|
||||
|
||||
egl->exts.KHR_platform_gbm = check_egl_ext(client_exts_str,
|
||||
"EGL_KHR_platform_gbm");
|
||||
egl->exts.EXT_platform_device = check_egl_ext(client_exts_str,
|
||||
"EGL_EXT_platform_device");
|
||||
egl->exts.KHR_display_reference = check_egl_ext(client_exts_str,
|
||||
|
|
@ -496,28 +493,6 @@ static EGLDeviceEXT get_egl_device_from_drm_fd(struct wlr_egl *egl,
|
|||
return egl_device;
|
||||
}
|
||||
|
||||
static int open_render_node(int drm_fd) {
|
||||
char *render_name = drmGetRenderDeviceNameFromFd(drm_fd);
|
||||
if (render_name == NULL) {
|
||||
// This can happen on split render/display platforms, fallback to
|
||||
// primary node
|
||||
render_name = drmGetPrimaryDeviceNameFromFd(drm_fd);
|
||||
if (render_name == NULL) {
|
||||
wlr_log_errno(WLR_ERROR, "drmGetPrimaryDeviceNameFromFd failed");
|
||||
return -1;
|
||||
}
|
||||
wlr_log(WLR_DEBUG, "DRM device '%s' has no render node, "
|
||||
"falling back to primary node", render_name);
|
||||
}
|
||||
|
||||
int render_fd = open(render_name, O_RDWR | O_CLOEXEC);
|
||||
if (render_fd < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to open DRM node '%s'", render_name);
|
||||
}
|
||||
free(render_name);
|
||||
return render_fd;
|
||||
}
|
||||
|
||||
struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
|
||||
struct wlr_egl *egl = egl_create();
|
||||
if (egl == NULL) {
|
||||
|
|
@ -525,49 +500,22 @@ struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (egl->exts.EXT_platform_device) {
|
||||
/*
|
||||
* Search for the EGL device matching the DRM fd using the
|
||||
* EXT_device_enumeration extension.
|
||||
*/
|
||||
EGLDeviceEXT egl_device = get_egl_device_from_drm_fd(egl, drm_fd);
|
||||
if (egl_device != EGL_NO_DEVICE_EXT) {
|
||||
if (egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) {
|
||||
wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_DEVICE_EXT");
|
||||
return egl;
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
/* Falls back on GBM in case the device was not found */
|
||||
} else {
|
||||
if (!egl->exts.EXT_platform_device) {
|
||||
wlr_log(WLR_DEBUG, "EXT_platform_device not supported");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (egl->exts.KHR_platform_gbm) {
|
||||
int gbm_fd = open_render_node(drm_fd);
|
||||
if (gbm_fd < 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to open DRM render node");
|
||||
goto error;
|
||||
}
|
||||
|
||||
egl->gbm_device = gbm_create_device(gbm_fd);
|
||||
if (!egl->gbm_device) {
|
||||
close(gbm_fd);
|
||||
wlr_log(WLR_ERROR, "Failed to create GBM device");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (egl_init(egl, EGL_PLATFORM_GBM_KHR, egl->gbm_device)) {
|
||||
wlr_log(WLR_DEBUG, "Using EGL_PLATFORM_GBM_KHR");
|
||||
return egl;
|
||||
}
|
||||
|
||||
gbm_device_destroy(egl->gbm_device);
|
||||
close(gbm_fd);
|
||||
} else {
|
||||
wlr_log(WLR_DEBUG, "KHR_platform_gbm not supported");
|
||||
EGLDeviceEXT egl_device = get_egl_device_from_drm_fd(egl, drm_fd);
|
||||
if (egl_device == EGL_NO_DEVICE_EXT) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!egl_init(egl, EGL_PLATFORM_DEVICE_EXT, egl_device)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return egl;
|
||||
|
||||
error:
|
||||
wlr_log(WLR_ERROR, "Failed to initialize EGL context");
|
||||
free(egl);
|
||||
|
|
@ -623,12 +571,6 @@ void wlr_egl_destroy(struct wlr_egl *egl) {
|
|||
|
||||
eglReleaseThread();
|
||||
|
||||
if (egl->gbm_device) {
|
||||
int gbm_fd = gbm_device_get_fd(egl->gbm_device);
|
||||
gbm_device_destroy(egl->gbm_device);
|
||||
close(gbm_fd);
|
||||
}
|
||||
|
||||
free(egl);
|
||||
}
|
||||
|
||||
|
|
@ -936,12 +878,7 @@ static char *get_render_name(const char *name) {
|
|||
if (match == NULL) {
|
||||
wlr_log(WLR_ERROR, "Cannot find DRM device %s", name);
|
||||
} else if (!(match->available_nodes & (1 << DRM_NODE_RENDER))) {
|
||||
// Likely a split display/render setup. Pick the primary node and hope
|
||||
// Mesa will open the right render node under-the-hood.
|
||||
wlr_log(WLR_DEBUG, "DRM device %s has no render node, "
|
||||
"falling back to primary node", name);
|
||||
assert(match->available_nodes & (1 << DRM_NODE_PRIMARY));
|
||||
render_name = strdup(match->nodes[DRM_NODE_PRIMARY]);
|
||||
wlr_log(WLR_ERROR, "DRM device has no render node");
|
||||
} else {
|
||||
render_name = strdup(match->nodes[DRM_NODE_RENDER]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,8 @@ endif
|
|||
|
||||
if 'gles2' in renderers or 'auto' in renderers
|
||||
egl = dependency('egl', required: 'gles2' in renderers)
|
||||
gbm = dependency('gbm', required: 'gles2' in renderers)
|
||||
if egl.found() and gbm.found()
|
||||
wlr_deps += [egl, gbm]
|
||||
if egl.found()
|
||||
wlr_deps += egl
|
||||
wlr_files += files('egl.c')
|
||||
internal_features += { 'egl': true }
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -376,32 +376,24 @@ int vulkan_open_phdev_drm_fd(VkPhysicalDevice phdev) {
|
|||
};
|
||||
vkGetPhysicalDeviceProperties2(phdev, &props);
|
||||
|
||||
dev_t devid;
|
||||
if (drm_props.hasRender) {
|
||||
devid = makedev(drm_props.renderMajor, drm_props.renderMinor);
|
||||
} else if (drm_props.hasPrimary) {
|
||||
devid = makedev(drm_props.primaryMajor, drm_props.primaryMinor);
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Physical device is missing both render and primary nodes");
|
||||
if (!drm_props.hasRender) {
|
||||
wlr_log(WLR_ERROR, "Physical device is missing render node");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev_t devid = makedev(drm_props.renderMajor, drm_props.renderMinor);
|
||||
drmDevice *device = NULL;
|
||||
if (drmGetDeviceFromDevId(devid, 0, &device) != 0) {
|
||||
wlr_log_errno(WLR_ERROR, "drmGetDeviceFromDevId failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *name = NULL;
|
||||
if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
|
||||
name = device->nodes[DRM_NODE_RENDER];
|
||||
} else {
|
||||
assert(device->available_nodes & (1 << DRM_NODE_PRIMARY));
|
||||
name = device->nodes[DRM_NODE_PRIMARY];
|
||||
wlr_log(WLR_DEBUG, "DRM device %s has no render node, "
|
||||
"falling back to primary node", name);
|
||||
if (!(device->available_nodes & (1 << DRM_NODE_RENDER))) {
|
||||
wlr_log(WLR_ERROR, "DRM device has no render node");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *name = device->nodes[DRM_NODE_RENDER];
|
||||
int drm_fd = open(name, O_RDWR | O_NONBLOCK | O_CLOEXEC);
|
||||
if (drm_fd < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to open DRM node %s", name);
|
||||
|
|
|
|||
|
|
@ -245,27 +245,42 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r,
|
|||
return true;
|
||||
}
|
||||
|
||||
static int open_drm_render_node(void) {
|
||||
static drmDevice **list_drm_devices(void) {
|
||||
uint32_t flags = 0;
|
||||
int devices_len = drmGetDevices2(flags, NULL, 0);
|
||||
if (devices_len < 0) {
|
||||
wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len));
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
drmDevice **devices = calloc(devices_len, sizeof(*devices));
|
||||
drmDevice **devices = calloc(devices_len + 1, sizeof(*devices));
|
||||
if (devices == NULL) {
|
||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
devices_len = drmGetDevices2(flags, devices, devices_len);
|
||||
if (devices_len < 0) {
|
||||
free(devices);
|
||||
wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len));
|
||||
return NULL;
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
static void destroy_drm_devices(drmDevice **devices) {
|
||||
for (size_t i = 0; devices[i] != NULL; i++) {
|
||||
drmFreeDevice(&devices[i]);
|
||||
}
|
||||
free(devices);
|
||||
}
|
||||
|
||||
static int open_drm_render_node(void) {
|
||||
drmDevice **devices = list_drm_devices();
|
||||
if (devices == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
for (int i = 0; i < devices_len; i++) {
|
||||
for (size_t i = 0; devices[i] != NULL; i++) {
|
||||
drmDevice *dev = devices[i];
|
||||
if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
|
||||
const char *name = dev->nodes[DRM_NODE_RENDER];
|
||||
|
|
@ -283,11 +298,73 @@ static int open_drm_render_node(void) {
|
|||
}
|
||||
|
||||
out:
|
||||
for (int i = 0; i < devices_len; i++) {
|
||||
drmFreeDevice(&devices[i]);
|
||||
}
|
||||
free(devices);
|
||||
destroy_drm_devices(devices);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int open_backend_drm_render_node(int backend_drm_fd) {
|
||||
// First, try to open the render node of the DRM device used by the backend
|
||||
drmDevice *dev = NULL;
|
||||
if (drmGetDevice2(backend_drm_fd, 0, &dev) != 0) {
|
||||
wlr_log(WLR_ERROR, "drmGetDevice2 failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
|
||||
const char *name = dev->nodes[DRM_NODE_RENDER];
|
||||
wlr_log(WLR_DEBUG, "Opening DRM render node '%s'", name);
|
||||
int fd = open(name, O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name);
|
||||
}
|
||||
drmFreeDevice(&dev);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (dev->bustype != DRM_BUS_PLATFORM) {
|
||||
wlr_log(WLR_ERROR, "DRM device '%s' does not have a render node",
|
||||
dev->nodes[DRM_NODE_PRIMARY]);
|
||||
drmFreeDevice(&dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
drmFreeDevice(&dev);
|
||||
|
||||
// Try to find another platform device with a render node
|
||||
drmDevice **devices = list_drm_devices();
|
||||
if (devices == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
for (size_t i = 0; devices[i] != NULL; i++) {
|
||||
drmDevice *dev = devices[i];
|
||||
if (dev->bustype != DRM_BUS_PLATFORM ||
|
||||
!(dev->available_nodes & (1 << DRM_NODE_RENDER))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
wlr_log(WLR_ERROR, "Found multiple platform device DRM render nodes");
|
||||
break;
|
||||
}
|
||||
|
||||
const char *name = dev->nodes[DRM_NODE_RENDER];
|
||||
wlr_log(WLR_DEBUG, "Opening platform device DRM render node '%s'", name);
|
||||
fd = open(name, O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name);
|
||||
goto out_devices;
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to find any platform device DRM render node");
|
||||
}
|
||||
|
||||
out_devices:
|
||||
destroy_drm_devices(devices);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
|
@ -318,11 +395,15 @@ static bool open_preferred_drm_fd(struct wlr_backend *backend, int *drm_fd_ptr,
|
|||
return true;
|
||||
}
|
||||
|
||||
// Prefer the backend's DRM node, if any
|
||||
// Prefer the backend's DRM device, if any
|
||||
int backend_drm_fd = wlr_backend_get_drm_fd(backend);
|
||||
if (backend_drm_fd >= 0) {
|
||||
*drm_fd_ptr = backend_drm_fd;
|
||||
*own_drm_fd = false;
|
||||
int drm_fd = open_backend_drm_render_node(backend_drm_fd);
|
||||
if (drm_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
*drm_fd_ptr = drm_fd;
|
||||
*own_drm_fd = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue