From 67d2fb6ec5723e1f25497f3a37edc3c8026eabba Mon Sep 17 00:00:00 2001 From: Phyzait Lu Date: Mon, 12 Jan 2026 01:14:47 +0800 Subject: [PATCH] render: respect WLR_DRM_DEVICES in open_drm_render_node When using WLR_BACKENDS=headless with WLR_DRM_DEVICES, the renderer would ignore the device selection and pick the first available render node. This is problematic for multi-GPU setups where a specific GPU should be used for rendering. Parse WLR_DRM_DEVICES (colon-separated) in open_drm_render_node() to allow selecting which DRM device to use, matching the behavior of the DRM backend. The specified path can be any node type (card, render, primary) and the corresponding render node will be opened. --- render/wlr_renderer.c | 72 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index e65314ccc..4c4b2a35b 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -113,19 +114,70 @@ static int open_drm_render_node(void) { } int fd = -1; - for (int i = 0; i < devices_len; i++) { - drmDevice *dev = devices[i]; - 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); - fd = open(name, O_RDWR | O_CLOEXEC); - if (fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); - goto out; + + const char *drm_devices_env = getenv("WLR_DRM_DEVICES"); + if (drm_devices_env) { + char *drm_devices = strdup(drm_devices_env); + if (drm_devices == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + goto out; + } + + char *saveptr; + char *token = strtok_r(drm_devices, ":", &saveptr); + while (token != NULL) { + bool found = false; + for (int i = 0; i < devices_len; i++) { + drmDevice *dev = devices[i]; + bool match = false; + for (int j = 0; j < DRM_NODE_MAX; j++) { + if ((dev->available_nodes & (1 << j)) && + strcmp(dev->nodes[j], token) == 0) { + match = true; + break; + } + } + + if (match) { + found = true; + if (!(dev->available_nodes & (1 << DRM_NODE_RENDER))) { + wlr_log(WLR_DEBUG, "Skipping DRM device '%s': no render node", token); + break; + } + const char *name = dev->nodes[DRM_NODE_RENDER]; + wlr_log(WLR_DEBUG, "Opening DRM render node '%s' from WLR_DRM_DEVICES", name); + fd = open(name, O_RDWR | O_CLOEXEC); + if (fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); + } + break; + } + } + if (fd >= 0) { + break; + } + if (!found) { + wlr_log(WLR_DEBUG, "DRM device '%s' not found", token); + } + token = strtok_r(NULL, ":", &saveptr); + } + free(drm_devices); + } else { + for (int i = 0; i < devices_len; i++) { + drmDevice *dev = devices[i]; + 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); + fd = open(name, O_RDWR | O_CLOEXEC); + if (fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to open '%s'", name); + goto out; + } + break; } - break; } } + if (fd < 0) { wlr_log(WLR_ERROR, "Failed to find any DRM render node"); }