diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index b273fef1..0b647484 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -101,7 +101,7 @@ static void atomic_add(struct atomic *atom, uint32_t id, uint32_t prop, uint64_t } } -bool create_mode_blob(struct wlr_drm_connector *conn, +static bool create_mode_blob(struct wlr_drm_connector *conn, const struct wlr_drm_connector_state *state, uint32_t *blob_id) { if (!state->active) { *blob_id = 0; @@ -117,7 +117,7 @@ bool create_mode_blob(struct wlr_drm_connector *conn, return true; } -bool create_gamma_lut_blob(struct wlr_drm_backend *drm, +static bool create_gamma_lut_blob(struct wlr_drm_backend *drm, size_t size, const uint16_t *lut, uint32_t *blob_id) { if (size == 0) { *blob_id = 0; @@ -233,51 +233,12 @@ static void rollback_blob(struct wlr_drm_backend *drm, destroy_blob(drm, next); } -static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) { - uint32_t id = plane->id; - const union wlr_drm_plane_props *props = &plane->props; - atomic_add(atom, id, props->fb_id, 0); - atomic_add(atom, id, props->crtc_id, 0); -} - -static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm, - struct wlr_drm_plane *plane, struct wlr_drm_fb *fb, uint32_t crtc_id, - int32_t x, int32_t y) { - uint32_t id = plane->id; - const union wlr_drm_plane_props *props = &plane->props; - - if (fb == NULL) { - wlr_log(WLR_ERROR, "Failed to acquire FB for plane %"PRIu32, plane->id); - atom->failed = true; - return; - } - - uint32_t width = fb->wlr_buf->width; - uint32_t height = fb->wlr_buf->height; - - // The src_* properties are in 16.16 fixed point - atomic_add(atom, id, props->src_x, 0); - atomic_add(atom, id, props->src_y, 0); - atomic_add(atom, id, props->src_w, (uint64_t)width << 16); - atomic_add(atom, id, props->src_h, (uint64_t)height << 16); - atomic_add(atom, id, props->crtc_w, width); - atomic_add(atom, id, props->crtc_h, height); - atomic_add(atom, id, props->fb_id, fb->id); - atomic_add(atom, id, props->crtc_id, crtc_id); - atomic_add(atom, id, props->crtc_x, (uint64_t)x); - atomic_add(atom, id, props->crtc_y, (uint64_t)y); -} - -static bool atomic_crtc_commit(struct wlr_drm_connector *conn, - const struct wlr_drm_connector_state *state, - struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only) { +bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, bool modeset) { + struct wlr_drm_connector *conn = state->connector; struct wlr_drm_backend *drm = conn->backend; struct wlr_output *output = &conn->output; struct wlr_drm_crtc *crtc = conn->crtc; - bool modeset = state->modeset; - bool active = state->active; - uint32_t mode_id = crtc->mode_id; if (modeset) { if (!create_mode_blob(conn, state, &mode_id)) { @@ -321,6 +282,87 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, vrr_enabled = state->base->adaptive_sync_enabled; } + state->mode_id = mode_id; + state->gamma_lut = gamma_lut; + state->fb_damage_clips = fb_damage_clips; + state->vrr_enabled = vrr_enabled; + return true; +} + +void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state) { + struct wlr_drm_connector *conn = state->connector; + struct wlr_drm_crtc *crtc = conn->crtc; + struct wlr_drm_backend *drm = conn->backend; + + if (!crtc->own_mode_id) { + crtc->mode_id = 0; // don't try to delete previous master's blobs + } + crtc->own_mode_id = true; + commit_blob(drm, &crtc->mode_id, state->mode_id); + commit_blob(drm, &crtc->gamma_lut, state->gamma_lut); + + destroy_blob(drm, state->fb_damage_clips); +} + +void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state) { + struct wlr_drm_connector *conn = state->connector; + struct wlr_drm_crtc *crtc = conn->crtc; + struct wlr_drm_backend *drm = conn->backend; + + rollback_blob(drm, &crtc->mode_id, state->mode_id); + rollback_blob(drm, &crtc->gamma_lut, state->gamma_lut); + + destroy_blob(drm, state->fb_damage_clips); +} + +static void plane_disable(struct atomic *atom, struct wlr_drm_plane *plane) { + uint32_t id = plane->id; + const union wlr_drm_plane_props *props = &plane->props; + atomic_add(atom, id, props->fb_id, 0); + atomic_add(atom, id, props->crtc_id, 0); +} + +static void set_plane_props(struct atomic *atom, struct wlr_drm_backend *drm, + struct wlr_drm_plane *plane, struct wlr_drm_fb *fb, uint32_t crtc_id, + int32_t x, int32_t y) { + uint32_t id = plane->id; + const union wlr_drm_plane_props *props = &plane->props; + + if (fb == NULL) { + wlr_log(WLR_ERROR, "Failed to acquire FB for plane %"PRIu32, plane->id); + atom->failed = true; + return; + } + + uint32_t width = fb->wlr_buf->width; + uint32_t height = fb->wlr_buf->height; + + // The src_* properties are in 16.16 fixed point + atomic_add(atom, id, props->src_x, 0); + atomic_add(atom, id, props->src_y, 0); + atomic_add(atom, id, props->src_w, (uint64_t)width << 16); + atomic_add(atom, id, props->src_h, (uint64_t)height << 16); + atomic_add(atom, id, props->crtc_w, width); + atomic_add(atom, id, props->crtc_h, height); + atomic_add(atom, id, props->fb_id, fb->id); + atomic_add(atom, id, props->crtc_id, crtc_id); + atomic_add(atom, id, props->crtc_x, (uint64_t)x); + atomic_add(atom, id, props->crtc_y, (uint64_t)y); +} + +static bool atomic_crtc_commit(struct wlr_drm_connector *conn, + struct wlr_drm_connector_state *state, + struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only) { + struct wlr_drm_backend *drm = conn->backend; + struct wlr_drm_crtc *crtc = conn->crtc; + + bool modeset = state->modeset; + bool active = state->active; + + if (!drm_atomic_connector_prepare(state, modeset)) { + return false; + } + if (test_only) { flags |= DRM_MODE_ATOMIC_TEST_ONLY; } @@ -345,20 +387,20 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, if (modeset && active && conn->props.max_bpc != 0 && conn->max_bpc_bounds[1] != 0) { atomic_add(&atom, conn->id, conn->props.max_bpc, pick_max_bpc(conn, state->primary_fb)); } - atomic_add(&atom, crtc->id, crtc->props.mode_id, mode_id); + atomic_add(&atom, crtc->id, crtc->props.mode_id, state->mode_id); atomic_add(&atom, crtc->id, crtc->props.active, active); if (active) { if (crtc->props.gamma_lut != 0) { - atomic_add(&atom, crtc->id, crtc->props.gamma_lut, gamma_lut); + atomic_add(&atom, crtc->id, crtc->props.gamma_lut, state->gamma_lut); } if (crtc->props.vrr_enabled != 0) { - atomic_add(&atom, crtc->id, crtc->props.vrr_enabled, vrr_enabled); + atomic_add(&atom, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled); } set_plane_props(&atom, drm, crtc->primary, state->primary_fb, crtc->id, 0, 0); if (crtc->primary->props.fb_damage_clips != 0) { atomic_add(&atom, crtc->primary->id, - crtc->primary->props.fb_damage_clips, fb_damage_clips); + crtc->primary->props.fb_damage_clips, state->fb_damage_clips); } if (crtc->cursor) { if (drm_connector_is_cursor_visible(conn)) { @@ -379,17 +421,10 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, atomic_finish(&atom); if (ok && !test_only) { - if (!crtc->own_mode_id) { - crtc->mode_id = 0; // don't try to delete previous master's blobs - } - crtc->own_mode_id = true; - commit_blob(drm, &crtc->mode_id, mode_id); - commit_blob(drm, &crtc->gamma_lut, gamma_lut); + drm_atomic_connector_apply_commit(state); } else { - rollback_blob(drm, &crtc->mode_id, mode_id); - rollback_blob(drm, &crtc->gamma_lut, gamma_lut); + drm_atomic_connector_rollback_commit(state); } - destroy_blob(drm, fb_damage_clips); return ok; } diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 9de8d33c..8b60c766 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -489,7 +489,7 @@ static void drm_connector_rollback_commit(const struct wlr_drm_connector_state * } static bool drm_crtc_commit(struct wlr_drm_connector *conn, - const struct wlr_drm_connector_state *state, + struct wlr_drm_connector_state *state, uint32_t flags, bool test_only) { // Disallow atomic-only flags assert((flags & ~DRM_MODE_PAGE_FLIP_FLAGS) == 0); diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index f8cabbd0..2eca165e 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -59,7 +59,7 @@ static bool legacy_crtc_test(struct wlr_drm_connector *conn, } static bool legacy_crtc_commit(struct wlr_drm_connector *conn, - const struct wlr_drm_connector_state *state, + struct wlr_drm_connector_state *state, struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only) { if (!legacy_crtc_test(conn, state)) { return false; diff --git a/backend/drm/libliftoff.c b/backend/drm/libliftoff.c index 2f51ae57..7df19f76 100644 --- a/backend/drm/libliftoff.c +++ b/backend/drm/libliftoff.c @@ -126,27 +126,6 @@ static bool add_prop(drmModeAtomicReq *req, uint32_t obj, return true; } -static void commit_blob(struct wlr_drm_backend *drm, - uint32_t *current, uint32_t next) { - if (*current == next) { - return; - } - if (*current != 0) { - drmModeDestroyPropertyBlob(drm->fd, *current); - } - *current = next; -} - -static void rollback_blob(struct wlr_drm_backend *drm, - uint32_t *current, uint32_t next) { - if (*current == next) { - return; - } - if (next != 0) { - drmModeDestroyPropertyBlob(drm->fd, next); - } -} - static bool set_plane_props(struct wlr_drm_plane *plane, struct liftoff_layer *layer, struct wlr_drm_fb *fb, int32_t x, int32_t y, uint64_t zpos) { if (fb == NULL) { @@ -301,10 +280,9 @@ static void update_layer_feedback(struct wlr_drm_backend *drm, } static bool crtc_commit(struct wlr_drm_connector *conn, - const struct wlr_drm_connector_state *state, + struct wlr_drm_connector_state *state, struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only) { struct wlr_drm_backend *drm = conn->backend; - struct wlr_output *output = &conn->output; struct wlr_drm_crtc *crtc = conn->crtc; bool modeset = state->modeset; @@ -314,53 +292,8 @@ static bool crtc_commit(struct wlr_drm_connector *conn, return false; } - uint32_t mode_id = crtc->mode_id; - if (modeset) { - if (!create_mode_blob(conn, state, &mode_id)) { - return false; - } - } - - uint32_t gamma_lut = crtc->gamma_lut; - if (state->base->committed & WLR_OUTPUT_STATE_GAMMA_LUT) { - // Fallback to legacy gamma interface when gamma properties are not - // available (can happen on older Intel GPUs that support gamma but not - // degamma). - if (crtc->props.gamma_lut == 0) { - if (!drm_legacy_crtc_set_gamma(drm, crtc, - state->base->gamma_lut_size, - state->base->gamma_lut)) { - return false; - } - } else { - if (!create_gamma_lut_blob(drm, state->base->gamma_lut_size, - state->base->gamma_lut, &gamma_lut)) { - return false; - } - } - } - - struct wl_array fb_damage_clips_arr = {0}; - - uint32_t primary_fb_damage_clips = 0; - if ((state->base->committed & WLR_OUTPUT_STATE_DAMAGE) && - crtc->primary->props.fb_damage_clips != 0) { - uint32_t *ptr = wl_array_add(&fb_damage_clips_arr, sizeof(primary_fb_damage_clips)); - if (ptr == NULL) { - return false; - } - create_fb_damage_clips_blob(drm, state->primary_fb->wlr_buf->width, - state->primary_fb->wlr_buf->height, &state->base->damage, - &primary_fb_damage_clips); - *ptr = primary_fb_damage_clips; - } - - bool prev_vrr_enabled = - output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED; - bool vrr_enabled = prev_vrr_enabled; - if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) && - drm_connector_supports_vrr(conn)) { - vrr_enabled = state->base->adaptive_sync_enabled; + if (!drm_atomic_connector_prepare(state, modeset)) { + return false; } if (test_only) { @@ -373,6 +306,7 @@ static bool crtc_commit(struct wlr_drm_connector *conn, flags |= DRM_MODE_ATOMIC_NONBLOCK; } + struct wl_array fb_damage_clips_arr = {0}; drmModeAtomicReq *req = drmModeAtomicAlloc(); if (req == NULL) { wlr_log(WLR_ERROR, "drmModeAtomicAlloc failed"); @@ -391,22 +325,22 @@ static bool crtc_commit(struct wlr_drm_connector *conn, } // TODO: set "max bpc" ok = ok && - add_prop(req, crtc->id, crtc->props.mode_id, mode_id) && + add_prop(req, crtc->id, crtc->props.mode_id, state->mode_id) && add_prop(req, crtc->id, crtc->props.active, active); if (active) { if (crtc->props.gamma_lut != 0) { - ok = ok && add_prop(req, crtc->id, crtc->props.gamma_lut, gamma_lut); + ok = ok && add_prop(req, crtc->id, crtc->props.gamma_lut, state->gamma_lut); } if (crtc->props.vrr_enabled != 0) { - ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, vrr_enabled); + ok = ok && add_prop(req, crtc->id, crtc->props.vrr_enabled, state->vrr_enabled); } ok = ok && set_plane_props(crtc->primary, crtc->primary->liftoff_layer, state->primary_fb, 0, 0, 0) && set_plane_props(crtc->primary, crtc->liftoff_composition_layer, state->primary_fb, 0, 0, 0); liftoff_layer_set_property(crtc->primary->liftoff_layer, - "FB_DAMAGE_CLIPS", primary_fb_damage_clips); + "FB_DAMAGE_CLIPS", state->fb_damage_clips); liftoff_layer_set_property(crtc->liftoff_composition_layer, - "FB_DAMAGE_CLIPS", primary_fb_damage_clips); + "FB_DAMAGE_CLIPS", state->fb_damage_clips); if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) { for (size_t i = 0; i < state->base->layers_len; i++) { @@ -475,15 +409,9 @@ out: drmModeAtomicFree(req); if (ok && !test_only) { - if (!crtc->own_mode_id) { - crtc->mode_id = 0; // don't try to delete previous master's blobs - } - crtc->own_mode_id = true; - commit_blob(drm, &crtc->mode_id, mode_id); - commit_blob(drm, &crtc->gamma_lut, gamma_lut); + drm_atomic_connector_apply_commit(state); } else { - rollback_blob(drm, &crtc->mode_id, mode_id); - rollback_blob(drm, &crtc->gamma_lut, gamma_lut); + drm_atomic_connector_rollback_commit(state); } uint32_t *fb_damage_clips_ptr; diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 309fd98d..fea1c478 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -131,6 +131,12 @@ struct wlr_drm_connector_state { drmModeModeInfo mode; struct wlr_drm_fb *primary_fb; struct wlr_drm_fb *cursor_fb; + + // used by atomic + uint32_t mode_id; + uint32_t gamma_lut; + uint32_t fb_damage_clips; + bool vrr_enabled; }; /** diff --git a/include/backend/drm/iface.h b/include/backend/drm/iface.h index 6408c440..3f688969 100644 --- a/include/backend/drm/iface.h +++ b/include/backend/drm/iface.h @@ -20,7 +20,7 @@ struct wlr_drm_interface { void (*finish)(struct wlr_drm_backend *drm); // Commit all pending changes on a CRTC. bool (*crtc_commit)(struct wlr_drm_connector *conn, - const struct wlr_drm_connector_state *state, + struct wlr_drm_connector_state *state, struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only); // Turn off everything bool (*reset)(struct wlr_drm_backend *drm); @@ -33,12 +33,13 @@ extern const struct wlr_drm_interface liftoff_iface; bool drm_legacy_crtc_set_gamma(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, size_t size, uint16_t *lut); -bool create_mode_blob(struct wlr_drm_connector *conn, - const struct wlr_drm_connector_state *state, uint32_t *blob_id); -bool create_gamma_lut_blob(struct wlr_drm_backend *drm, - size_t size, const uint16_t *lut, uint32_t *blob_id); bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm, int width, int height, const pixman_region32_t *damage, uint32_t *blob_id); bool drm_atomic_reset(struct wlr_drm_backend *drm); +bool drm_atomic_connector_prepare(struct wlr_drm_connector_state *state, + bool modeset); +void drm_atomic_connector_apply_commit(struct wlr_drm_connector_state *state); +void drm_atomic_connector_rollback_commit(struct wlr_drm_connector_state *state); + #endif