diff options
-rw-r--r-- | backend/CMakeLists.txt | 1 | ||||
-rw-r--r-- | backend/drm/backend.c | 23 | ||||
-rw-r--r-- | backend/drm/drm.c | 65 | ||||
-rw-r--r-- | backend/drm/event.c | 93 | ||||
-rw-r--r-- | backend/drm/udev.c | 69 | ||||
-rw-r--r-- | include/backend/drm/backend.h | 17 | ||||
-rw-r--r-- | include/backend/drm/event.h | 25 | ||||
-rw-r--r-- | include/backend/drm/udev.h | 5 |
8 files changed, 114 insertions, 184 deletions
diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index 2d6e734f..344dd3cc 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -11,7 +11,6 @@ add_library(wlr-backend wayland/wl_output.c drm/backend.c drm/drm.c - drm/event.c drm/session.c drm/udev.c ) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index da7ca1e4..769a4a5c 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -6,7 +6,6 @@ #include "backend/drm/backend.h" #include "backend/drm/drm.h" -#include "backend/drm/event.h" #include "backend/drm/session.h" #include "backend/drm/udev.h" #include "common/log.h" @@ -19,12 +18,18 @@ struct wlr_drm_backend *wlr_drm_backend_init(void) return NULL; } + backend->event_loop = wl_event_loop_create(); + if (!backend->event_loop) { + wlr_log(L_ERROR, "Failed to create event loop"); + goto error_backend; + } + if (!wlr_session_start(&backend->session)) { wlr_log(L_ERROR, "Failed to start session"); - goto error; + goto error_loop; } - if (!wlr_udev_init(&backend->udev)) { + if (!wlr_udev_init(backend)) { wlr_log(L_ERROR, "Failed to start udev"); goto error_session; } @@ -40,6 +45,10 @@ struct wlr_drm_backend *wlr_drm_backend_init(void) goto error_fd; } + wl_signal_init(&backend->signals.display_add); + wl_signal_init(&backend->signals.display_rem); + wl_signal_init(&backend->signals.display_render); + wlr_drm_scan_connectors(backend); return backend; @@ -50,7 +59,9 @@ error_udev: wlr_udev_free(&backend->udev); error_session: wlr_session_end(&backend->session); -error: +error_loop: + wl_event_loop_destroy(backend->event_loop); +error_backend: free(backend); return NULL; } @@ -69,7 +80,9 @@ void wlr_drm_backend_free(struct wlr_drm_backend *backend) wlr_session_release_device(&backend->session, backend->fd); wlr_session_end(&backend->session); - free(backend->events); + wl_event_source_remove(backend->event_src.drm); + wl_event_loop_destroy(backend->event_loop); + free(backend->displays); free(backend); } diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 94d79e5c..d1d68224 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -11,10 +11,10 @@ #include <EGL/eglext.h> #include <gbm.h> #include <GLES3/gl3.h> +#include <wayland-server.h> #include "backend/drm/backend.h" #include "backend/drm/drm.h" -#include "backend/drm/event.h" #include "common/log.h" static const char *conn_name[] = { @@ -134,6 +134,33 @@ static bool egl_get_config(EGLDisplay disp, EGLConfig *out) return false; } +static void page_flip_handler(int fd, + unsigned seq, + unsigned tv_sec, + unsigned tv_usec, + void *user) +{ + struct wlr_drm_display *disp = user; + struct wlr_drm_backend *backend = disp->renderer->backend; + + disp->pageflip_pending = true; + if (!disp->cleanup) + wl_signal_emit(&backend->signals.display_render, disp); +} + + +static int drm_event(int fd, uint32_t mask, void *data) +{ + drmEventContext event = { + .version = DRM_EVENT_CONTEXT_VERSION, + .page_flip_handler = page_flip_handler, + }; + + drmHandleEvent(fd, &event); + + return 1; +} + bool wlr_drm_renderer_init(struct wlr_drm_renderer *renderer, struct wlr_drm_backend *backend, int fd) { @@ -177,6 +204,13 @@ bool wlr_drm_renderer_init(struct wlr_drm_renderer *renderer, goto error_egl; } + backend->event_src.drm = wl_event_loop_add_fd(backend->event_loop, + backend->fd, WL_EVENT_READABLE, drm_event, NULL); + if (!backend->event_src.drm) { + wlr_log(L_ERROR, "Failed to create DRM event source"); + goto error_egl; + } + renderer->fd = fd; renderer->backend = backend; @@ -252,13 +286,13 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) if (disp->state == DRM_DISP_DISCONNECTED && conn->connection == DRM_MODE_CONNECTED) { disp->state = DRM_DISP_NEEDS_MODESET; - wlr_drm_add_event(backend, disp, DRM_EV_DISPLAY_ADD); + wl_signal_emit(&backend->signals.display_add, disp); } else if (disp->state == DRM_DISP_CONNECTED && conn->connection != DRM_MODE_CONNECTED) { disp->state = DRM_DISP_DISCONNECTED; wlr_drm_display_free(disp, false); - wlr_drm_add_event(backend, disp, DRM_EV_DISPLAY_REM); + wl_signal_emit(&backend->signals.display_rem, disp); } drmModeFreeConnector(conn); @@ -488,24 +522,11 @@ error: drmModeFreeConnector(conn); free(disp->modes); - wlr_drm_add_event(backend, disp, DRM_EV_DISPLAY_REM); + wl_signal_emit(&backend->signals.display_rem, disp); return false; } -static void page_flip_handler(int fd, - unsigned seq, - unsigned tv_sec, - unsigned tv_usec, - void *user) -{ - struct wlr_drm_display *disp = user; - - disp->pageflip_pending = true; - if (!disp->cleanup) - wlr_drm_add_event(disp->renderer->backend, disp, DRM_EV_RENDER); -} - void wlr_drm_display_free(struct wlr_drm_display *disp, bool restore) { if (!disp || disp->state != DRM_DISP_CONNECTED) @@ -542,16 +563,6 @@ void wlr_drm_display_free(struct wlr_drm_display *disp, bool restore) } } -void wlr_drm_event(int fd) -{ - drmEventContext event = { - .version = DRM_EVENT_CONTEXT_VERSION, - .page_flip_handler = page_flip_handler, - }; - - drmHandleEvent(fd, &event); -} - void wlr_drm_display_begin(struct wlr_drm_display *disp) { struct wlr_drm_renderer *renderer = disp->renderer; diff --git a/backend/drm/event.c b/backend/drm/event.c deleted file mode 100644 index db17b5b7..00000000 --- a/backend/drm/event.c +++ /dev/null @@ -1,93 +0,0 @@ -#include <stdbool.h> -#include <stdlib.h> -#include <poll.h> - -#include "backend/drm/backend.h" -#include "backend/drm/event.h" -#include "backend/drm/drm.h" -#include "backend/drm/udev.h" - -static inline void event_swap(struct wlr_drm_event *a, struct wlr_drm_event *b) -{ - struct wlr_drm_event tmp = *a; - *a = *b; - *b = tmp; -} - -bool wlr_drm_get_event(struct wlr_drm_backend *backend, - struct wlr_drm_event *restrict ret) -{ - struct pollfd fds[] = { - { .fd = backend->fd, .events = POLLIN }, - { .fd = backend->udev.mon_fd, .events = POLLIN }, - }; - - while (poll(fds, 2, 0) > 0) { - if (fds[0].revents) - wlr_drm_event(backend->fd); - if (fds[1].revents) - wlr_udev_event(backend); - } - - if (backend->event_len == 0) { - ret->type = DRM_EV_NONE; - ret->display = NULL; - return false; - } - - struct wlr_drm_event *ev = backend->events; - - // Downheap - *ret = ev[0]; - ev[0] = ev[--backend->event_len]; - - size_t i = 0; - while (i < backend->event_len / 2) { - size_t left = i * 2 + 1; - size_t right = i * 2 + 2; - size_t max = (ev[left].type > ev[right].type) ? left : right; - - if (ev[i].type <= ev[max].type) { - event_swap(&ev[i], &ev[max]); - i = max; - } else { - break; - } - } - - return true; -} - -bool wlr_drm_add_event(struct wlr_drm_backend *backend, - struct wlr_drm_display *disp, enum wlr_drm_event_type type) -{ - if (type == DRM_EV_NONE) - return true; - - if (backend->event_len == backend->event_cap) { - size_t new_size = (backend->event_cap == 0) ? 8 : backend->event_cap * 2; - - struct wlr_drm_event *new = realloc(backend->events, sizeof *new * new_size); - if (!new) { - return false; - } - - backend->event_cap = new_size; - backend->events = new; - } - - struct wlr_drm_event *ev = backend->events; - - // Upheap - size_t i = backend->event_len++; - ev[i].type = type; - ev[i].display = disp; - - size_t j; - while (i > 0 && ev[i].type > ev[(j = (i - 1) / 2)].type) { - event_swap(&ev[i], &ev[j]); - i = j; - } - - return true; -} diff --git a/backend/drm/udev.c b/backend/drm/udev.c index ebc68c6b..6c4aa074 100644 --- a/backend/drm/udev.c +++ b/backend/drm/udev.c @@ -7,6 +7,7 @@ #include <stdint.h> #include <xf86drm.h> #include <xf86drmMode.h> +#include <wayland-server.h> #include "backend/drm/backend.h" #include "backend/drm/udev.h" @@ -116,8 +117,34 @@ int wlr_udev_find_gpu(struct wlr_udev *udev, struct wlr_session *session) return fd; } -bool wlr_udev_init(struct wlr_udev *udev) +static int udev_event(int fd, uint32_t mask, void *data) { + struct wlr_drm_backend *backend = data; + struct wlr_udev *udev = &backend->udev; + + struct udev_device *dev = udev_monitor_receive_device(udev->mon); + if (!dev) + return 1; + + const char *path = udev_device_get_devnode(dev); + if (!path || strcmp(path, udev->drm_path) != 0) + goto out; + + const char *action = udev_device_get_action(dev); + if (!action || strcmp(action, "change") != 0) + goto out; + + wlr_drm_scan_connectors(backend); + +out: + udev_device_unref(dev); + return 1; +} + +bool wlr_udev_init(struct wlr_drm_backend *backend) +{ + struct wlr_udev *udev = &backend->udev; + udev->udev = udev_new(); if (!udev->udev) { wlr_log(L_ERROR, "Failed to create udev context"); @@ -127,17 +154,29 @@ bool wlr_udev_init(struct wlr_udev *udev) udev->mon = udev_monitor_new_from_netlink(udev->udev, "udev"); if (!udev->mon) { wlr_log(L_ERROR, "Failed to create udev monitor"); - udev_unref(udev->udev); - return false; + goto error_udev; } udev_monitor_filter_add_match_subsystem_devtype(udev->mon, "drm", NULL); udev_monitor_enable_receiving(udev->mon); - udev->mon_fd = udev_monitor_get_fd(udev->mon); + backend->event_src.udev = wl_event_loop_add_fd(backend->event_loop, + udev_monitor_get_fd(udev->mon), WL_EVENT_READABLE, + udev_event, backend); + if (!backend->event_src.udev) { + wlr_log(L_ERROR, "Failed to create udev event source"); + goto error_mon; + } + udev->drm_path = NULL; return true; + +error_mon: + udev_monitor_unref(udev->mon); +error_udev: + udev_unref(udev->udev); + return false; } void wlr_udev_free(struct wlr_udev *udev) @@ -150,25 +189,3 @@ void wlr_udev_free(struct wlr_udev *udev) udev_unref(udev->udev); free(udev->drm_path); } - -void wlr_udev_event(struct wlr_drm_backend *backend) -{ - struct wlr_udev *udev = &backend->udev; - - struct udev_device *dev = udev_monitor_receive_device(udev->mon); - if (!dev) - return; - - const char *path = udev_device_get_devnode(dev); - if (!path || strcmp(path, udev->drm_path) != 0) - goto out; - - const char *action = udev_device_get_action(dev); - if (!action || strcmp(action, "change") != 0) - goto out; - - wlr_drm_scan_connectors(backend); - -out: - udev_device_unref(dev); -} diff --git a/include/backend/drm/backend.h b/include/backend/drm/backend.h index caa18bcc..25a42c37 100644 --- a/include/backend/drm/backend.h +++ b/include/backend/drm/backend.h @@ -6,6 +6,7 @@ #include <EGL/egl.h> #include <gbm.h> #include <libudev.h> +#include <wayland-server.h> #include "session.h" #include "udev.h" @@ -16,10 +17,18 @@ struct wlr_drm_backend { int fd; bool paused; - // Priority Queue (Max-heap) - size_t event_cap; - size_t event_len; - struct wlr_drm_event *events; + struct wl_event_loop *event_loop; + + struct { + struct wl_event_source *drm; + struct wl_event_source *udev; + } event_src; + + struct { + struct wl_signal display_add; + struct wl_signal display_rem; + struct wl_signal display_render; + } signals; size_t display_len; struct wlr_drm_display *displays; diff --git a/include/backend/drm/event.h b/include/backend/drm/event.h deleted file mode 100644 index 2155bd32..00000000 --- a/include/backend/drm/event.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef EVENT_H -#define EVENT_H - -#include <stdbool.h> -#include "drm.h" - -enum wlr_drm_event_type { - DRM_EV_NONE, - DRM_EV_RENDER, - DRM_EV_DISPLAY_REM, - DRM_EV_DISPLAY_ADD, -}; - -struct wlr_drm_event { - enum wlr_drm_event_type type; - struct wlr_drm_display *display; -}; - -struct wlr_drm_backend; -bool wlr_drm_get_event(struct wlr_drm_backend *backend, - struct wlr_drm_event *restrict ret); -bool wlr_drm_add_event(struct wlr_drm_backend *backend, - struct wlr_drm_display *disp, enum wlr_drm_event_type type); - -#endif diff --git a/include/backend/drm/udev.h b/include/backend/drm/udev.h index 6b10c9ec..576b5d6e 100644 --- a/include/backend/drm/udev.h +++ b/include/backend/drm/udev.h @@ -8,15 +8,14 @@ struct wlr_udev { struct udev *udev; struct udev_monitor *mon; - int mon_fd; char *drm_path; }; -bool wlr_udev_init(struct wlr_udev *udev); +struct wlr_drm_backend; +bool wlr_udev_init(struct wlr_drm_backend *backend); void wlr_udev_free(struct wlr_udev *udev); int wlr_udev_find_gpu(struct wlr_udev *udev, struct wlr_session *session); -struct wlr_drm_backend; void wlr_udev_event(struct wlr_drm_backend *backend); #endif |