diff options
Diffstat (limited to 'backend')
-rw-r--r-- | backend/drm/drm.c | 12 | ||||
-rw-r--r-- | backend/drm/libliftoff.c | 60 | ||||
-rw-r--r-- | backend/drm/meson.build | 2 |
3 files changed, 73 insertions, 1 deletions
diff --git a/backend/drm/drm.c b/backend/drm/drm.c index b0b36a4e..10966940 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -349,6 +349,7 @@ static void layer_handle_addon_destroy(struct wlr_addon *addon) { drm_fb_clear(&layer->pending_fb); drm_fb_clear(&layer->queued_fb); drm_fb_clear(&layer->current_fb); + free(layer->candidate_planes); free(layer); } @@ -381,6 +382,8 @@ static struct wlr_drm_layer *get_or_create_layer(struct wlr_drm_backend *drm, return NULL; } + layer->wlr = wlr_layer; + #if HAVE_LIBLIFTOFF layer->liftoff = liftoff_layer_create(crtc->liftoff); if (layer->liftoff == NULL) { @@ -391,6 +394,15 @@ static struct wlr_drm_layer *get_or_create_layer(struct wlr_drm_backend *drm, abort(); // unreachable #endif + layer->candidate_planes = calloc(sizeof(bool), drm->num_planes); + if (layer->candidate_planes == NULL) { +#if HAVE_LIBLIFTOFF + liftoff_layer_destroy(layer->liftoff); +#endif + free(layer); + return NULL; + } + wlr_addon_init(&layer->addon, &wlr_layer->addons, drm, &layer_impl); wl_list_insert(&crtc->layers, &layer->link); diff --git a/backend/drm/libliftoff.c b/backend/drm/libliftoff.c index 1ba75416..812ce7f8 100644 --- a/backend/drm/libliftoff.c +++ b/backend/drm/libliftoff.c @@ -1,6 +1,7 @@ #define _POSIX_C_SOURCE 200809L #include <fcntl.h> #include <libliftoff.h> +#include <sys/stat.h> #include <unistd.h> #include <wlr/util/log.h> @@ -214,6 +215,62 @@ static bool set_layer_props(struct wlr_drm_backend *drm, liftoff_layer_set_property(layer->liftoff, "SRC_H", src_h) == 0; } +static bool devid_from_fd(int fd, dev_t *devid) { + struct stat stat; + if (fstat(fd, &stat) != 0) { + wlr_log_errno(WLR_ERROR, "fstat failed"); + return false; + } + *devid = stat.st_rdev; + return true; +} + +static void update_layer_feedback(struct wlr_drm_backend *drm, + struct wlr_drm_layer *layer) { + bool changed = false; + for (size_t i = 0; i < drm->num_planes; i++) { + struct wlr_drm_plane *plane = &drm->planes[i]; + bool is_candidate = liftoff_layer_is_candidate_plane(layer->liftoff, + plane->liftoff); + if (layer->candidate_planes[i] != is_candidate) { + layer->candidate_planes[i] = is_candidate; + changed = true; + } + } + if (!changed) { + return; + } + + dev_t target_device; + if (!devid_from_fd(drm->fd, &target_device)) { + return; + } + + struct wlr_drm_format_set formats = {0}; + for (size_t i = 0; i < drm->num_planes; i++) { + struct wlr_drm_plane *plane = &drm->planes[i]; + if (!layer->candidate_planes[i]) { + continue; + } + + for (size_t j = 0; j < plane->formats.len; j++) { + const struct wlr_drm_format *format = plane->formats.formats[j]; + for (size_t k = 0; k < format->len; k++) { + wlr_drm_format_set_add(&formats, format->format, + format->modifiers[k]); + } + } + } + + struct wlr_output_layer_feedback_event event = { + .target_device = target_device, + .formats = &formats, + }; + wl_signal_emit_mutable(&layer->wlr->events.feedback, &event); + + wlr_drm_format_set_finish(&formats); +} + static bool crtc_commit(struct wlr_drm_connector *conn, const struct wlr_drm_connector_state *state, uint32_t flags, bool test_only) { @@ -380,6 +437,9 @@ static bool crtc_commit(struct wlr_drm_connector *conn, struct wlr_drm_layer *layer = get_drm_layer(drm, layer_state->layer); layer_state->accepted = !liftoff_layer_needs_composition(layer->liftoff); + if (!test_only && !layer_state->accepted) { + update_layer_feedback(drm, layer); + } } } diff --git a/backend/drm/meson.build b/backend/drm/meson.build index 8d1c1845..3fb011c1 100644 --- a/backend/drm/meson.build +++ b/backend/drm/meson.build @@ -7,7 +7,7 @@ hwdata = dependency( libliftoff = dependency( 'libliftoff', - version: '>=0.2.0', + version: '>=0.4.0', fallback: 'libliftoff', required: false, ) |