diff --git a/kick.c b/kick.c index 2b9787a..d86a51f 100644 --- a/kick.c +++ b/kick.c @@ -39,10 +39,14 @@ const char *__ubsan_default_options(void) { #include #include #include +#include #include +#include #include #include #include +#include +#include #include @@ -13124,6 +13128,46 @@ static bool started_on_console(void) { 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[]) { snprintf(kick_socket, sizeof(kick_socket), "kick-%d", (int)getpid()); @@ -13634,7 +13678,27 @@ int main(int argc, char *argv[]) { server.renderer); wlr_subcompositor_create(server.wl_display); 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_ext_data_control_manager_v1_create(server.wl_display, 1); diff --git a/meson.build b/meson.build index d558e55..46a1db9 100644 --- a/meson.build +++ b/meson.build @@ -36,6 +36,8 @@ deps = [ dependency('pixman-1'), # Server-side/client-side window decorations via libdecor (nested mode). dependency('libdecor-0'), + # libdrm for render-node discovery (dmabuf main device override). + dependency('libdrm'), ] cc = meson.get_compiler('c')