aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/wayland/backend.c134
-rw-r--r--backend/wayland/meson.build1
-rw-r--r--include/backend/wayland.h2
3 files changed, 117 insertions, 20 deletions
diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c
index 7d7eeaf5..53da3604 100644
--- a/backend/wayland/backend.c
+++ b/backend/wayland/backend.c
@@ -10,6 +10,7 @@
#include <drm_fourcc.h>
#include <wayland-server-core.h>
+#include <xf86drm.h>
#include <wlr/backend/interface.h>
#include <wlr/interfaces/wlr_input_device.h>
@@ -23,6 +24,7 @@
#include "render/wlr_renderer.h"
#include "util/signal.h"
+#include "drm-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "pointer-gestures-unstable-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
@@ -99,6 +101,91 @@ static const struct zwp_linux_dmabuf_v1_listener linux_dmabuf_v1_listener = {
.modifier = linux_dmabuf_v1_handle_modifier,
};
+static bool device_has_name(const drmDevice *device, const char *name) {
+ for (size_t i = 0; i < DRM_NODE_MAX; i++) {
+ if (!(device->available_nodes & (1 << i))) {
+ continue;
+ }
+ if (strcmp(device->nodes[i], name) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static char *get_render_name(const char *name) {
+ uint32_t flags = 0;
+ int devices_len = drmGetDevices2(flags, NULL, 0);
+ if (devices_len < 0) {
+ wlr_log(WLR_ERROR, "drmGetDevices2 failed");
+ return NULL;
+ }
+ drmDevice **devices = calloc(devices_len, sizeof(drmDevice *));
+ if (devices == NULL) {
+ wlr_log_errno(WLR_ERROR, "Allocation failed");
+ return NULL;
+ }
+ devices_len = drmGetDevices2(flags, devices, devices_len);
+ if (devices_len < 0) {
+ free(devices);
+ wlr_log(WLR_ERROR, "drmGetDevices2 failed");
+ return NULL;
+ }
+
+ const drmDevice *match = NULL;
+ for (int i = 0; i < devices_len; i++) {
+ if (device_has_name(devices[i], name)) {
+ match = devices[i];
+ break;
+ }
+ }
+
+ char *render_name = NULL;
+ if (match == NULL) {
+ wlr_log(WLR_ERROR, "Cannot find DRM device %s", name);
+ } else if (!(match->available_nodes & (1 << DRM_NODE_RENDER))) {
+ wlr_log(WLR_ERROR, "DRM device %s has no render node", name);
+ } else {
+ render_name = strdup(match->nodes[DRM_NODE_RENDER]);
+ }
+
+ for (int i = 0; i < devices_len; i++) {
+ drmFreeDevice(&devices[i]);
+ }
+ free(devices);
+
+ return render_name;
+}
+
+static void legacy_drm_handle_device(void *data, struct wl_drm *drm,
+ const char *name) {
+ struct wlr_wl_backend *wl = data;
+
+ // TODO: get FD from linux-dmabuf hints instead
+ wl->drm_render_name = get_render_name(name);
+}
+
+static void legacy_drm_handle_format(void *data, struct wl_drm *drm,
+ uint32_t format) {
+ // This space is intentionally left blank
+}
+
+static void legacy_drm_handle_authenticated(void *data, struct wl_drm *drm) {
+ // This space is intentionally left blank
+}
+
+static void legacy_drm_handle_capabilities(void *data, struct wl_drm *drm,
+ uint32_t caps) {
+ // This space is intentionally left blank
+}
+
+static const struct wl_drm_listener legacy_drm_listener = {
+ .device = legacy_drm_handle_device,
+ .format = legacy_drm_handle_format,
+ .authenticated = legacy_drm_handle_authenticated,
+ .capabilities = legacy_drm_handle_capabilities,
+};
+
static void registry_global(void *data, struct wl_registry *registry,
uint32_t name, const char *iface, uint32_t version) {
struct wlr_wl_backend *wl = data;
@@ -139,6 +226,9 @@ static void registry_global(void *data, struct wl_registry *registry,
} else if (strcmp(iface, zwp_relative_pointer_manager_v1_interface.name) == 0) {
wl->zwp_relative_pointer_manager_v1 = wl_registry_bind(registry, name,
&zwp_relative_pointer_manager_v1_interface, 1);
+ } else if (strcmp(iface, wl_drm_interface.name) == 0) {
+ wl->legacy_drm = wl_registry_bind(registry, name, &wl_drm_interface, 1);
+ wl_drm_add_listener(wl->legacy_drm, &legacy_drm_listener, wl);
}
}
@@ -205,6 +295,7 @@ static void backend_destroy(struct wlr_backend *backend) {
wl_event_source_remove(wl->remote_display_src);
wlr_renderer_destroy(wl->renderer);
+ wlr_allocator_destroy(wl->allocator);
wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats);
@@ -229,6 +320,7 @@ static void backend_destroy(struct wlr_backend *backend) {
if (wl->zwp_relative_pointer_manager_v1) {
zwp_relative_pointer_manager_v1_destroy(wl->zwp_relative_pointer_manager_v1);
}
+ free(wl->drm_render_name);
xdg_wm_base_destroy(wl->xdg_wm_base);
wl_compositor_destroy(wl->compositor);
wl_registry_destroy(wl->registry);
@@ -301,6 +393,11 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
"Remote Wayland compositor does not support xdg-shell");
goto error_registry;
}
+ if (!wl->drm_render_name) {
+ wlr_log(WLR_ERROR, "Failed to get DRM render node from remote Wayland "
+ "compositor wl_drm interface");
+ goto error_registry;
+ }
struct wl_event_loop *loop = wl_display_get_event_loop(wl->local_display);
int fd = wl_display_get_fd(wl->remote_display);
@@ -312,32 +409,28 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
}
wl_event_source_check(wl->remote_display_src);
- wl->renderer = wlr_renderer_autocreate(EGL_PLATFORM_WAYLAND_EXT,
- wl->remote_display);
- if (!wl->renderer) {
- wlr_log(WLR_ERROR, "Could not create renderer");
- goto error_event;
- }
-
- // TODO: get FD from linux-dmabuf hints instead
- int drm_fd = wlr_renderer_get_drm_fd(wl->renderer);
+ wlr_log(WLR_DEBUG, "Opening DRM render node %s", wl->drm_render_name);
+ int drm_fd = open(wl->drm_render_name, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (drm_fd < 0) {
- wlr_log(WLR_ERROR, "Failed to get DRM device FD from renderer");
- goto error_event;
+ wlr_log_errno(WLR_ERROR, "Failed to open DRM render node %s",
+ wl->drm_render_name);
+ goto error_registry;
}
- drm_fd = fcntl(drm_fd, F_DUPFD_CLOEXEC, 0);
- if (drm_fd < 0) {
- wlr_log_errno(WLR_ERROR, "fcntl(F_DUPFD_CLOEXEC) failed");
- goto error_event;
+ struct wlr_gbm_allocator *gbm_alloc = wlr_gbm_allocator_create(drm_fd);
+ if (gbm_alloc == NULL) {
+ wlr_log(WLR_ERROR, "Failed to create GBM allocator");
+ close(drm_fd);
+ goto error_registry;
}
+ wl->allocator = &gbm_alloc->base;
- struct wlr_gbm_allocator *alloc = wlr_gbm_allocator_create(drm_fd);
- if (alloc == NULL) {
- wlr_log(WLR_ERROR, "Failed to create GBM allocator");
- goto error_event;
+ wl->renderer = wlr_renderer_autocreate(EGL_PLATFORM_GBM_KHR,
+ gbm_alloc->gbm_device);
+ if (wl->renderer == NULL) {
+ wlr_log(WLR_ERROR, "Failed to create renderer");
+ goto error_registry;
}
- wl->allocator = &alloc->base;
uint32_t fmt = DRM_FORMAT_ARGB8888;
const struct wlr_drm_format *remote_format =
@@ -376,6 +469,7 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
error_event:
wl_event_source_remove(wl->remote_display_src);
error_registry:
+ free(wl->drm_render_name);
if (wl->compositor) {
wl_compositor_destroy(wl->compositor);
}
diff --git a/backend/wayland/meson.build b/backend/wayland/meson.build
index d23f114e..85b5d697 100644
--- a/backend/wayland/meson.build
+++ b/backend/wayland/meson.build
@@ -6,6 +6,7 @@ wlr_files += files(
)
client_protos = [
+ 'drm',
'linux-dmabuf-unstable-v1',
'pointer-gestures-unstable-v1',
'presentation-time',
diff --git a/include/backend/wayland.h b/include/backend/wayland.h
index e0e8ee37..3f30bc77 100644
--- a/include/backend/wayland.h
+++ b/include/backend/wayland.h
@@ -42,6 +42,8 @@ struct wlr_wl_backend {
struct wl_list seats; // wlr_wl_seat.link
struct zwp_tablet_manager_v2 *tablet_manager;
struct wlr_drm_format_set linux_dmabuf_v1_formats;
+ struct wl_drm *legacy_drm;
+ char *drm_render_name;
};
struct wlr_wl_buffer {