mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-17 06:46:39 -04:00
Merge branch 'drm-layer-fbs' into 'master'
Draft: backend/drm: track layer FBs in wlr_drm_connector_state See merge request wlroots/wlroots!4589
This commit is contained in:
commit
cac1b1cd71
3 changed files with 54 additions and 75 deletions
|
|
@ -419,7 +419,6 @@ static void layer_handle_addon_destroy(struct wlr_addon *addon) {
|
||||||
#if HAVE_LIBLIFTOFF
|
#if HAVE_LIBLIFTOFF
|
||||||
liftoff_layer_destroy(layer->liftoff);
|
liftoff_layer_destroy(layer->liftoff);
|
||||||
#endif
|
#endif
|
||||||
drm_fb_clear(&layer->pending_fb);
|
|
||||||
drm_fb_clear(&layer->queued_fb);
|
drm_fb_clear(&layer->queued_fb);
|
||||||
drm_fb_clear(&layer->current_fb);
|
drm_fb_clear(&layer->current_fb);
|
||||||
free(layer->candidate_planes);
|
free(layer->candidate_planes);
|
||||||
|
|
@ -554,6 +553,7 @@ static void drm_connector_set_pending_page_flip(struct wlr_drm_connector *conn,
|
||||||
static void drm_connector_apply_commit(const struct wlr_drm_connector_state *state,
|
static void drm_connector_apply_commit(const struct wlr_drm_connector_state *state,
|
||||||
struct wlr_drm_page_flip *page_flip) {
|
struct wlr_drm_page_flip *page_flip) {
|
||||||
struct wlr_drm_connector *conn = state->connector;
|
struct wlr_drm_connector *conn = state->connector;
|
||||||
|
struct wlr_drm_backend *drm = conn->backend;
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
|
|
||||||
drm_fb_copy(&crtc->primary->queued_fb, state->primary_fb);
|
drm_fb_copy(&crtc->primary->queued_fb, state->primary_fb);
|
||||||
|
|
@ -563,9 +563,13 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
|
||||||
}
|
}
|
||||||
drm_fb_clear(&conn->cursor_pending_fb);
|
drm_fb_clear(&conn->cursor_pending_fb);
|
||||||
|
|
||||||
struct wlr_drm_layer *layer;
|
if (crtc->liftoff) {
|
||||||
wl_list_for_each(layer, &crtc->layers, link) {
|
for (size_t i = 0; i < state->base->layers_len; i++) {
|
||||||
drm_fb_move(&layer->queued_fb, &layer->pending_fb);
|
struct wlr_output_layer_state *layer_state = &state->base->layers[i];
|
||||||
|
struct wlr_drm_layer *layer = get_or_create_layer(drm, crtc, layer_state->layer);
|
||||||
|
assert(layer != NULL);
|
||||||
|
drm_fb_copy(&layer->queued_fb, state->layer_fbs[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_connector_set_pending_page_flip(conn, page_flip);
|
drm_connector_set_pending_page_flip(conn, page_flip);
|
||||||
|
|
@ -584,22 +588,6 @@ static void drm_connector_apply_commit(const struct wlr_drm_connector_state *sta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_connector_rollback_commit(const struct wlr_drm_connector_state *state) {
|
|
||||||
struct wlr_drm_crtc *crtc = state->connector->crtc;
|
|
||||||
|
|
||||||
// The set_cursor() hook is a bit special: it's not really synchronized
|
|
||||||
// to commit() or test(). Once set_cursor() returns true, the new
|
|
||||||
// cursor is effectively committed. So don't roll it back here, or we
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool drm_commit(struct wlr_drm_backend *drm,
|
static bool drm_commit(struct wlr_drm_backend *drm,
|
||||||
const struct wlr_drm_device_state *state,
|
const struct wlr_drm_device_state *state,
|
||||||
uint32_t flags, bool test_only) {
|
uint32_t flags, bool test_only) {
|
||||||
|
|
@ -621,15 +609,18 @@ static bool drm_commit(struct wlr_drm_backend *drm,
|
||||||
drm_connector_apply_commit(&state->connectors[i], page_flip);
|
drm_connector_apply_commit(&state->connectors[i], page_flip);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t i = 0; i < state->connectors_len; i++) {
|
// The set_cursor() hook is a bit special: it's not really synchronized
|
||||||
drm_connector_rollback_commit(&state->connectors[i]);
|
// to commit() or test(). Once set_cursor() returns true, the new
|
||||||
}
|
// cursor is effectively committed. So don't roll it back here, or we
|
||||||
|
// 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.
|
||||||
drm_page_flip_destroy(page_flip);
|
drm_page_flip_destroy(page_flip);
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_connector_state_init(struct wlr_drm_connector_state *state,
|
static bool drm_connector_state_init(struct wlr_drm_connector_state *state,
|
||||||
struct wlr_drm_connector *conn,
|
struct wlr_drm_connector *conn,
|
||||||
const struct wlr_output_state *base) {
|
const struct wlr_output_state *base) {
|
||||||
*state = (struct wlr_drm_connector_state){
|
*state = (struct wlr_drm_connector_state){
|
||||||
|
|
@ -667,6 +658,13 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
|
||||||
state->mode.type = DRM_MODE_TYPE_USERDEF;
|
state->mode.type = DRM_MODE_TYPE_USERDEF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (base->layers_len > 0) {
|
||||||
|
state->layer_fbs = calloc(base->layers_len, sizeof(state->layer_fbs[0]));
|
||||||
|
if (state->layer_fbs == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (output_pending_enabled(&conn->output, base)) {
|
if (output_pending_enabled(&conn->output, base)) {
|
||||||
// The CRTC must be set up before this function is called
|
// The CRTC must be set up before this function is called
|
||||||
assert(conn->crtc != NULL);
|
assert(conn->crtc != NULL);
|
||||||
|
|
@ -691,13 +689,32 @@ static void drm_connector_state_init(struct wlr_drm_connector_state *state,
|
||||||
state->cursor_fb = drm_fb_lock(cursor->current_fb);
|
state->cursor_fb = drm_fb_lock(cursor->current_fb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!conn->backend->parent && conn->crtc->liftoff) {
|
||||||
|
for (size_t i = 0; i < base->layers_len; i++) {
|
||||||
|
struct wlr_output_layer_state *layer_state = &base->layers[i];
|
||||||
|
if (layer_state->buffer != NULL) {
|
||||||
|
drm_fb_import(&state->layer_fbs[i], conn->backend, layer_state->buffer, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (get_or_create_layer(conn->backend, conn->crtc, layer_state->layer) == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drm_connector_state_finish(struct wlr_drm_connector_state *state) {
|
static void drm_connector_state_finish(struct wlr_drm_connector_state *state) {
|
||||||
drm_fb_clear(&state->primary_fb);
|
drm_fb_clear(&state->primary_fb);
|
||||||
drm_fb_clear(&state->cursor_fb);
|
drm_fb_clear(&state->cursor_fb);
|
||||||
wlr_drm_syncobj_timeline_unref(state->wait_timeline);
|
wlr_drm_syncobj_timeline_unref(state->wait_timeline);
|
||||||
|
for (size_t i = 0; i < state->base->layers_len; i++) {
|
||||||
|
drm_fb_clear(&state->layer_fbs[i]);
|
||||||
|
}
|
||||||
|
free(state->layer_fbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn,
|
static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn,
|
||||||
|
|
@ -770,39 +787,6 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool drm_connector_set_pending_layer_fbs(struct wlr_drm_connector *conn,
|
|
||||||
const struct wlr_output_state *state) {
|
|
||||||
struct wlr_drm_backend *drm = conn->backend;
|
|
||||||
|
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
|
||||||
if (!crtc || drm->parent) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!crtc->liftoff) {
|
|
||||||
return true; // libliftoff is disabled
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(state->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 *layer =
|
|
||||||
get_or_create_layer(drm, crtc, layer_state->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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool drm_connector_alloc_crtc(struct wlr_drm_connector *conn);
|
static bool drm_connector_alloc_crtc(struct wlr_drm_connector *conn);
|
||||||
|
|
||||||
static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bool test_only) {
|
static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bool test_only) {
|
||||||
|
|
@ -850,11 +834,6 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
|
|
||||||
if (!drm_connector_set_pending_layer_fbs(conn, conn_state->base)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conn_state->active && !conn_state->primary_fb) {
|
if (conn_state->active && !conn_state->primary_fb) {
|
||||||
wlr_drm_conn_log(conn, WLR_DEBUG,
|
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||||
|
|
@ -886,7 +865,9 @@ static bool drm_connector_commit_state(struct wlr_drm_connector *conn,
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
struct wlr_drm_connector_state pending = {0};
|
struct wlr_drm_connector_state pending = {0};
|
||||||
drm_connector_state_init(&pending, conn, state);
|
if (!drm_connector_state_init(&pending, conn, state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
struct wlr_drm_device_state pending_dev = {
|
struct wlr_drm_device_state pending_dev = {
|
||||||
.modeset = state->allow_reconfiguration,
|
.modeset = state->allow_reconfiguration,
|
||||||
// The wlr_output API requires non-modeset commits with a new buffer to
|
// The wlr_output API requires non-modeset commits with a new buffer to
|
||||||
|
|
@ -1884,7 +1865,9 @@ bool commit_drm_device(struct wlr_drm_backend *drm,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_drm_connector_state *conn_state = &conn_states[conn_states_len];
|
struct wlr_drm_connector_state *conn_state = &conn_states[conn_states_len];
|
||||||
drm_connector_state_init(conn_state, conn, &output_state->base);
|
if (!drm_connector_state_init(conn_state, conn, &output_state->base)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
conn_states_len++;
|
conn_states_len++;
|
||||||
|
|
||||||
if (!drm_connector_prepare(conn_state, test_only)) {
|
if (!drm_connector_prepare(conn_state, test_only)) {
|
||||||
|
|
|
||||||
|
|
@ -180,8 +180,8 @@ static uint64_t to_fp16(double v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool set_layer_props(struct wlr_drm_backend *drm,
|
static bool set_layer_props(struct wlr_drm_backend *drm,
|
||||||
const struct wlr_output_layer_state *state, uint64_t zpos,
|
const struct wlr_output_layer_state *state, struct wlr_drm_fb *fb,
|
||||||
struct wl_array *fb_damage_clips_arr) {
|
uint64_t zpos, struct wl_array *fb_damage_clips_arr) {
|
||||||
struct wlr_drm_layer *layer = get_drm_layer(drm, state->layer);
|
struct wlr_drm_layer *layer = get_drm_layer(drm, state->layer);
|
||||||
|
|
||||||
uint32_t width = 0, height = 0;
|
uint32_t width = 0, height = 0;
|
||||||
|
|
@ -190,7 +190,6 @@ static bool set_layer_props(struct wlr_drm_backend *drm,
|
||||||
height = state->buffer->height;
|
height = state->buffer->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_drm_fb *fb = layer->pending_fb;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
if (state->buffer == NULL) {
|
if (state->buffer == NULL) {
|
||||||
ret = liftoff_layer_set_property(layer->liftoff, "FB_ID", 0);
|
ret = liftoff_layer_set_property(layer->liftoff, "FB_ID", 0);
|
||||||
|
|
@ -358,12 +357,10 @@ static bool add_connector(drmModeAtomicReq *req,
|
||||||
(uintptr_t)&state->out_fence_fd);
|
(uintptr_t)&state->out_fence_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->base->committed & WLR_OUTPUT_STATE_LAYERS) {
|
|
||||||
for (size_t i = 0; i < state->base->layers_len; i++) {
|
for (size_t i = 0; i < state->base->layers_len; i++) {
|
||||||
const struct wlr_output_layer_state *layer_state = &state->base->layers[i];
|
const struct wlr_output_layer_state *layer_state = &state->base->layers[i];
|
||||||
ok = ok && set_layer_props(drm, layer_state, i + 1,
|
ok = ok && set_layer_props(drm, layer_state,
|
||||||
fb_damage_clips_arr);
|
state->layer_fbs[i], i + 1, fb_damage_clips_arr);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crtc->cursor) {
|
if (crtc->cursor) {
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,6 @@ struct wlr_drm_layer {
|
||||||
struct wlr_addon addon; // wlr_output_layer.addons
|
struct wlr_addon addon; // wlr_output_layer.addons
|
||||||
struct wl_list link; // wlr_drm_crtc.layers
|
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 */
|
/* Buffer submitted to the kernel, will be presented on next vblank */
|
||||||
struct wlr_drm_fb *queued_fb;
|
struct wlr_drm_fb *queued_fb;
|
||||||
/* Buffer currently displayed on screen */
|
/* Buffer currently displayed on screen */
|
||||||
|
|
@ -148,6 +146,7 @@ struct wlr_drm_connector_state {
|
||||||
struct wlr_drm_fb *primary_fb;
|
struct wlr_drm_fb *primary_fb;
|
||||||
struct wlr_drm_viewport primary_viewport;
|
struct wlr_drm_viewport primary_viewport;
|
||||||
struct wlr_drm_fb *cursor_fb;
|
struct wlr_drm_fb *cursor_fb;
|
||||||
|
struct wlr_drm_fb **layer_fbs; // same length as base.layers_len
|
||||||
|
|
||||||
struct wlr_drm_syncobj_timeline *wait_timeline;
|
struct wlr_drm_syncobj_timeline *wait_timeline;
|
||||||
uint64_t wait_point;
|
uint64_t wait_point;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue