mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
render: open platform device render node
Right now we rely on Mesa's renderonly/kmsro to handle split render/display systems. And we have a bunch of special cases in wlroots to accomodate for the fact we don't know about the render node. However, after a recent discussion [1], it appears we should be able to handle split render/display systems ourselves. If the backend is using a platform display-only device, we can pick a platform render-only device. This should work for all known split render/display SoCs. [1]: https://gitlab.freedesktop.org/mesa/mesa/-/issues/9920
This commit is contained in:
parent
5fb0007e02
commit
a69a6ae391
1 changed files with 93 additions and 12 deletions
|
|
@ -245,27 +245,42 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_drm_render_node(void) {
|
static drmDevice **list_drm_devices(void) {
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
int devices_len = drmGetDevices2(flags, NULL, 0);
|
int devices_len = drmGetDevices2(flags, NULL, 0);
|
||||||
if (devices_len < 0) {
|
if (devices_len < 0) {
|
||||||
wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len));
|
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) {
|
if (devices == NULL) {
|
||||||
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
wlr_log_errno(WLR_ERROR, "Allocation failed");
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
devices_len = drmGetDevices2(flags, devices, devices_len);
|
devices_len = drmGetDevices2(flags, devices, devices_len);
|
||||||
if (devices_len < 0) {
|
if (devices_len < 0) {
|
||||||
free(devices);
|
free(devices);
|
||||||
wlr_log(WLR_ERROR, "drmGetDevices2 failed: %s", strerror(-devices_len));
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = -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];
|
drmDevice *dev = devices[i];
|
||||||
if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
|
if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
|
||||||
const char *name = dev->nodes[DRM_NODE_RENDER];
|
const char *name = dev->nodes[DRM_NODE_RENDER];
|
||||||
|
|
@ -283,11 +298,73 @@ static int open_drm_render_node(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
for (int i = 0; i < devices_len; i++) {
|
destroy_drm_devices(devices);
|
||||||
drmFreeDevice(&devices[i]);
|
return fd;
|
||||||
}
|
}
|
||||||
free(devices);
|
|
||||||
|
|
||||||
|
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;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,11 +395,15 @@ static bool open_preferred_drm_fd(struct wlr_backend *backend, int *drm_fd_ptr,
|
||||||
return true;
|
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);
|
int backend_drm_fd = wlr_backend_get_drm_fd(backend);
|
||||||
if (backend_drm_fd >= 0) {
|
if (backend_drm_fd >= 0) {
|
||||||
*drm_fd_ptr = backend_drm_fd;
|
int drm_fd = open_backend_drm_render_node(backend_drm_fd);
|
||||||
*own_drm_fd = false;
|
if (drm_fd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*drm_fd_ptr = drm_fd;
|
||||||
|
*own_drm_fd = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue