From c2a624e8f6da8974d23ca0a71db3358577a09f7e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Feb 2023 11:10:31 +0100 Subject: [PATCH] backend/drm: move pending layer FB to wlr_drm_connector_state Introduce struct wlr_drm_layer_state to hold temporary per-commit layer state. Store pending FBs there, to mirror wlr_drm_connector_state.primary_fb. --- backend/drm/drm.c | 66 ++++++++++++++++++++++++--------------- backend/drm/libliftoff.c | 26 +++++++-------- include/backend/drm/drm.h | 9 ++++-- 3 files changed, 59 insertions(+), 42 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 2c660b8e1..47dba13d1 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -346,7 +346,6 @@ static void layer_handle_addon_destroy(struct wlr_addon *addon) { #if HAVE_LIBLIFTOFF liftoff_layer_destroy(layer->liftoff); #endif - drm_fb_clear(&layer->pending_fb); drm_fb_clear(&layer->queued_fb); drm_fb_clear(&layer->current_fb); free(layer->candidate_planes); @@ -427,9 +426,16 @@ static bool drm_crtc_commit(struct wlr_drm_connector *conn, drm_fb_move(&crtc->cursor->queued_fb, &conn->cursor_pending_fb); } - struct wlr_drm_layer *layer; - wl_list_for_each(layer, &crtc->layers, link) { - drm_fb_move(&layer->queued_fb, &layer->pending_fb); + if (crtc->liftoff != NULL) { + for (size_t i = 0; i < state->layers_len; i++) { + struct wlr_drm_layer_state *layer_state = &state->layers[i]; + struct wlr_drm_layer *layer = + get_drm_layer(drm, layer_state->base->layer); + drm_fb_clear(&layer->queued_fb); + if (layer_state->fb != NULL && layer_state->base->accepted) { + layer->queued_fb = drm_fb_lock(layer_state->fb); + } + } } } else { // The set_cursor() hook is a bit special: it's not really synchronized @@ -438,11 +444,6 @@ static bool drm_crtc_commit(struct wlr_drm_connector *conn, // risk ending up in a state where we don't have a cursor FB but // wlr_drm_connector.cursor_enabled is true. // TODO: fix our output interface to avoid this issue. - - struct wlr_drm_layer *layer; - wl_list_for_each(layer, &crtc->layers, link) { - drm_fb_clear(&layer->pending_fb); - } } return ok; } @@ -485,10 +486,27 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state, state->primary_fb = drm_fb_lock(primary->current_fb); } } + + if (base->committed & WLR_OUTPUT_STATE_LAYERS) { + state->layers = calloc(base->layers_len, sizeof(state->layers[0])); + if (state->layers == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return; + } + state->layers_len = base->layers_len; + + for (size_t i = 0; i < base->layers_len; i++) { + state->layers[i].base = &base->layers[i]; + } + } } static void drm_connector_state_finish(struct wlr_drm_connector_state *state) { drm_fb_clear(&state->primary_fb); + for (size_t i = 0; i < state->layers_len; i++) { + drm_fb_clear(&state->layers[i].fb); + } + free(state->layers); } static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn, @@ -540,8 +558,8 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn return true; } -static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn, - const struct wlr_output_state *state) { +static bool drm_connector_state_update_layer_fbs(struct wlr_drm_connector *conn, + struct wlr_drm_connector_state *state) { struct wlr_drm_backend *drm = conn->backend; struct wlr_drm_crtc *crtc = conn->crtc; @@ -553,20 +571,18 @@ static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn, return true; // libliftoff is disabled } - assert(state->committed & WLR_OUTPUT_STATE_LAYERS); + assert(state->base->committed & WLR_OUTPUT_STATE_LAYERS); for (size_t i = 0; i < state->layers_len; i++) { - struct wlr_output_layer_state *layer_state = &state->layers[i]; + struct wlr_drm_layer_state *layer_state = &state->layers[i]; struct wlr_drm_layer *layer = - get_or_create_layer(drm, crtc, layer_state->layer); + get_or_create_layer(drm, crtc, layer_state->base->layer); if (!layer) { return false; } - if (layer_state->buffer != NULL) { - drm_fb_import(&layer->pending_fb, drm, layer_state->buffer, NULL); - } else { - drm_fb_clear(&layer->pending_fb); + if (layer_state->base->buffer != NULL) { + drm_fb_import(&layer_state->fb, drm, layer_state->base->buffer, NULL); } } @@ -649,10 +665,9 @@ static bool drm_connector_test(struct wlr_output *output, goto out; } } - if (state->committed & WLR_OUTPUT_STATE_LAYERS) { - if (!drm_connector_set_pending_layer_fbs(conn, pending.base)) { - return false; - } + if ((state->committed & WLR_OUTPUT_STATE_LAYERS) && + !drm_connector_state_update_layer_fbs(conn, &pending)) { + return false; } ok = drm_crtc_commit(conn, &pending, 0, true); @@ -739,10 +754,9 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn, if (pending.modeset && pending.active) { flags |= DRM_MODE_PAGE_FLIP_EVENT; } - if (pending.base->committed & WLR_OUTPUT_STATE_LAYERS) { - if (!drm_connector_set_pending_layer_fbs(conn, pending.base)) { - return false; - } + if ((pending.base->committed & WLR_OUTPUT_STATE_LAYERS) && + !drm_connector_state_update_layer_fbs(conn, &pending)) { + return false; } if (pending.modeset) { diff --git a/backend/drm/libliftoff.c b/backend/drm/libliftoff.c index 90525d242..686b0ba06 100644 --- a/backend/drm/libliftoff.c +++ b/backend/drm/libliftoff.c @@ -174,18 +174,18 @@ static uint64_t to_fp16(double v) { } static bool set_layer_props(struct wlr_drm_backend *drm, - const struct wlr_output_layer_state *state, uint64_t zpos) { - struct wlr_drm_layer *layer = get_drm_layer(drm, state->layer); + const struct wlr_drm_layer_state *state, uint64_t zpos) { + struct wlr_drm_layer *layer = get_drm_layer(drm, state->base->layer); uint32_t width = 0, height = 0; - if (state->buffer != NULL) { - width = state->buffer->width; - height = state->buffer->height; + if (state->base->buffer != NULL) { + width = state->base->buffer->width; + height = state->base->buffer->height; } - struct wlr_drm_fb *fb = layer->pending_fb; + struct wlr_drm_fb *fb = state->fb; int ret = 0; - if (state->buffer == NULL) { + if (state->base->buffer == NULL) { ret = liftoff_layer_set_property(layer->liftoff, "FB_ID", 0); } else if (fb == NULL) { liftoff_layer_set_fb_composited(layer->liftoff); @@ -196,8 +196,8 @@ static bool set_layer_props(struct wlr_drm_backend *drm, return false; } - uint64_t crtc_x = (uint64_t)state->x; - uint64_t crtc_y = (uint64_t)state->y; + uint64_t crtc_x = (uint64_t)state->base->x; + uint64_t crtc_y = (uint64_t)state->base->y; uint64_t crtc_w = (uint64_t)width; uint64_t crtc_h = (uint64_t)height; @@ -383,11 +383,9 @@ static bool crtc_commit(struct wlr_drm_connector *conn, liftoff_layer_set_property(crtc->liftoff_composition_layer, "FB_DAMAGE_CLIPS", fb_damage_clips); - if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) { - for (size_t i = 0; i < state->base->layers_len; i++) { - const struct wlr_output_layer_state *layer_state = &state->base->layers[i]; - ok = ok && set_layer_props(drm, layer_state, i + 1); - } + for (size_t i = 0; i < state->layers_len; i++) { + const struct wlr_drm_layer_state *layer_state = &state->layers[i]; + ok = ok && set_layer_props(drm, layer_state, i + 1); } if (crtc->cursor) { diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 4b92c5eb3..b230019bf 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -43,8 +43,6 @@ struct wlr_drm_layer { struct wlr_addon addon; // wlr_output_layer.addons struct wl_list link; // wlr_drm_crtc.layers - /* Buffer to be submitted to the kernel on the next page-flip */ - struct wlr_drm_fb *pending_fb; /* Buffer submitted to the kernel, will be presented on next vblank */ struct wlr_drm_fb *queued_fb; /* Buffer currently displayed on screen */ @@ -127,6 +125,13 @@ struct wlr_drm_connector_state { bool active; drmModeModeInfo mode; struct wlr_drm_fb *primary_fb; + struct wlr_drm_layer_state *layers; + size_t layers_len; +}; + +struct wlr_drm_layer_state { + struct wlr_output_layer_state *base; + struct wlr_drm_fb *fb; }; struct wlr_drm_connector {