aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/drm/backend.c49
-rw-r--r--backend/drm/drm.c41
2 files changed, 75 insertions, 15 deletions
diff --git a/backend/drm/backend.c b/backend/drm/backend.c
index a7e736bb..255384fb 100644
--- a/backend/drm/backend.c
+++ b/backend/drm/backend.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <errno.h>
#include <wayland-server.h>
+#include <sys/stat.h>
#include <wlr/session.h>
#include <wlr/types.h>
@@ -41,6 +42,39 @@ static struct wlr_backend_impl backend_impl = {
.destroy = wlr_drm_backend_destroy
};
+static void device_paused(struct wl_listener *listener, void *data) {
+ struct wlr_backend_state *drm = wl_container_of(listener, drm, device_paused);
+ struct device_arg *arg = data;
+
+ // TODO: Actually pause the renderer or something.
+ // We currently just expect it to fail its next pageflip.
+
+ if (arg->dev == drm->dev) {
+ wlr_log(L_INFO, "DRM fd paused");
+ }
+}
+
+static void device_resumed(struct wl_listener *listener, void *data) {
+ struct wlr_backend_state *drm = wl_container_of(listener, drm, device_resumed);
+ struct device_arg *arg = data;
+
+ if (arg->dev != drm->dev) {
+ return;
+ }
+
+ if (dup2(arg->fd, drm->fd) < 0) {
+ wlr_log(L_ERROR, "dup2 failed: %s", strerror(errno));
+ return;
+ }
+
+ wlr_log(L_INFO, "DRM fd resumed");
+
+ for (size_t i = 0; i < drm->outputs->length; ++i) {
+ struct wlr_output_state *output = drm->outputs->items[i];
+ wlr_drm_output_start_renderer(output);
+ }
+}
+
struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
struct wlr_session *session) {
struct wlr_backend_state *state = calloc(1, sizeof(struct wlr_backend_state));
@@ -74,6 +108,12 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
goto error_udev;
}
+ struct stat st;
+ if (fstat(state->fd, &st) < 0) {
+ wlr_log(L_ERROR, "Stat failed: %s", strerror(errno));
+ }
+ state->dev = st.st_rdev;
+
struct wl_event_loop *event_loop = wl_display_get_event_loop(display);
state->drm_event = wl_event_loop_add_fd(event_loop, state->fd,
@@ -83,6 +123,15 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
goto error_fd;
}
+ wl_list_init(&state->device_paused.link);
+ wl_list_init(&state->device_paused.link);
+
+ state->device_paused.notify = device_paused;
+ state->device_resumed.notify = device_resumed;
+
+ wl_signal_add(&session->device_paused, &state->device_paused);
+ wl_signal_add(&session->device_resumed, &state->device_resumed);
+
// TODO: what is the difference between the per-output renderer and this
// one?
if (!wlr_drm_renderer_init(&state->renderer, state->fd)) {
diff --git a/backend/drm/drm.c b/backend/drm/drm.c
index fa91745f..483c923c 100644
--- a/backend/drm/drm.c
+++ b/backend/drm/drm.c
@@ -116,23 +116,13 @@ static void wlr_drm_output_end(struct wlr_output_state *output) {
output->pageflip_pending = true;
}
-static bool display_init_renderer(struct wlr_drm_renderer *renderer,
- struct wlr_output_state *output) {
- struct wlr_output_mode *mode = output->wlr_output->current_mode;
- output->renderer = renderer;
- output->gbm = gbm_surface_create(renderer->gbm, mode->width,
- mode->height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
- if (!output->gbm) {
- wlr_log(L_ERROR, "Failed to create GBM surface for %s: %s", output->name,
- strerror(errno));
- return false;
+void wlr_drm_output_start_renderer(struct wlr_output_state *output) {
+ if (output->state != DRM_OUTPUT_CONNECTED) {
+ return;
}
- output->egl = wlr_egl_create_surface(&renderer->egl, output->gbm);
- if (output->egl == EGL_NO_SURFACE) {
- wlr_log(L_ERROR, "Failed to create EGL surface for %s", output->name);
- return false;
- }
+ struct wlr_drm_renderer *renderer = output->renderer;
+ struct wlr_output_mode *mode = output->wlr_output->current_mode;
// Render black frame
eglMakeCurrent(renderer->egl.display, output->egl, output->egl, renderer->egl.context);
@@ -152,6 +142,27 @@ static bool display_init_renderer(struct wlr_drm_renderer *renderer,
DRM_MODE_PAGE_FLIP_EVENT, output);
gbm_surface_release_buffer(output->gbm, bo);
+}
+
+static bool display_init_renderer(struct wlr_drm_renderer *renderer,
+ struct wlr_output_state *output) {
+ struct wlr_output_mode *mode = output->wlr_output->current_mode;
+ output->renderer = renderer;
+ output->gbm = gbm_surface_create(renderer->gbm, mode->width,
+ mode->height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+ if (!output->gbm) {
+ wlr_log(L_ERROR, "Failed to create GBM surface for %s: %s", output->name,
+ strerror(errno));
+ return false;
+ }
+
+ output->egl = wlr_egl_create_surface(&renderer->egl, output->gbm);
+ if (output->egl == EGL_NO_SURFACE) {
+ wlr_log(L_ERROR, "Failed to create EGL surface for %s", output->name);
+ return false;
+ }
+
+ wlr_drm_output_start_renderer(output);
return true;
}