fix: advertise a render node as the dmabuf main device

On split display/render platforms (vc4 display + v3d render) the
GLES2 renderer resolves to the display node, which has no 3D engine
-- and wlroots then advertises that node as the dmabuf main device,
so Mesa clients try to render there and fall back to llvmpipe (mpv
goes software, drops hundreds of frames).  Discover a real render
node under /dev/dri and override the advertised main device with it;
rendering, allocation and scanout paths are untouched, and a missing
node falls back to the previous renderer-derived behavior.
This commit is contained in:
Andrew Hamilton 2026-09-23 13:25:19 +10:00
parent 689ab662f8
commit 31f413ff9f
2 changed files with 67 additions and 1 deletions

66
kick.c
View file

@ -39,10 +39,14 @@ const char *__ubsan_default_options(void) {
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/poll.h> #include <sys/poll.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/stat.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/sysmacros.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h>
#include <xf86drm.h>
#include <drm_fourcc.h> #include <drm_fourcc.h>
@ -13124,6 +13128,46 @@ static bool started_on_console(void) {
return true; return true;
} }
/* Split display/render platforms (vc4 display + v3d render): the GLES2
renderer resolves to the display node, which has no 3D engine -- and
wlroots would then advertise that node as the dmabuf main device, so
Mesa clients try to render there and fall back to llvmpipe (mpv goes
software). Find a real render node and report it instead; rendering,
allocation and scanout paths are untouched, only the advertisement.
Skips software rasterizers; the caller keeps the renderer-derived
device when nothing usable is found. */
static bool dmabuf_render_node(dev_t *dev_out) {
DIR *d = opendir("/dev/dri");
if (!d)
return false;
bool found = false;
struct dirent *e;
while ((e = readdir(d)) != NULL) {
if (strncmp(e->d_name, "renderD", 7) != 0)
continue;
char path[16 + NAME_MAX];
snprintf(path, sizeof(path), "/dev/dri/%s", e->d_name);
int fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0)
continue;
drmVersionPtr v = drmGetVersion(fd);
bool hw = v && v->name && strcmp(v->name, "swrast") != 0 &&
strcmp(v->name, "kmsro") != 0;
struct stat st;
if (hw && fstat(fd, &st) == 0) {
*dev_out = st.st_rdev;
found = true;
}
if (v)
drmFreeVersion(v);
close(fd);
if (found)
break;
}
closedir(d);
return found;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
snprintf(kick_socket, sizeof(kick_socket), "kick-%d", snprintf(kick_socket, sizeof(kick_socket), "kick-%d",
(int)getpid()); (int)getpid());
@ -13634,7 +13678,27 @@ int main(int argc, char *argv[]) {
server.renderer); server.renderer);
wlr_subcompositor_create(server.wl_display); wlr_subcompositor_create(server.wl_display);
wlr_shm_create_with_renderer(server.wl_display, 1, server.renderer); wlr_shm_create_with_renderer(server.wl_display, 1, server.renderer);
wlr_linux_dmabuf_v1_create_with_renderer(server.wl_display, 5, server.renderer); /* Advertise a render node, not the display node, as the dmabuf main
device (see dmabuf_render_node): on failure keep wlroots' default
renderer-derived device rather than dropping dmabuf entirely. */
struct wlr_linux_dmabuf_feedback_v1_init_options dmabuf_opts = {
.main_renderer = server.renderer,
};
struct wlr_linux_dmabuf_feedback_v1 dmabuf_feedback = {0};
if (wlr_linux_dmabuf_feedback_v1_init_with_options(&dmabuf_feedback,
&dmabuf_opts)) {
dev_t render_dev;
if (dmabuf_render_node(&render_dev)) {
dmabuf_feedback.main_device = render_dev;
kick_log(KICK_LOG_INFO, "[dmabuf] main device %u:%u (render node)\n",
major(render_dev), minor(render_dev));
}
wlr_linux_dmabuf_v1_create(server.wl_display, 5, &dmabuf_feedback);
wlr_linux_dmabuf_feedback_v1_finish(&dmabuf_feedback);
} else {
wlr_linux_dmabuf_v1_create_with_renderer(server.wl_display, 5,
server.renderer);
}
wlr_data_device_manager_create(server.wl_display); wlr_data_device_manager_create(server.wl_display);
wlr_ext_data_control_manager_v1_create(server.wl_display, 1); wlr_ext_data_control_manager_v1_create(server.wl_display, 1);

View file

@ -36,6 +36,8 @@ deps = [
dependency('pixman-1'), dependency('pixman-1'),
# Server-side/client-side window decorations via libdecor (nested mode). # Server-side/client-side window decorations via libdecor (nested mode).
dependency('libdecor-0'), dependency('libdecor-0'),
# libdrm for render-node discovery (dmabuf main device override).
dependency('libdrm'),
] ]
cc = meson.get_compiler('c') cc = meson.get_compiler('c')