mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-11-20 06:59:42 -05:00
output: atomic mode, enabled, scale and transform
This commit makes more output properties (mode, enabled, scale and transform) atomic. This means that they are double-buffered and only applied on commit. Compositors now need to call wlr_output_commit after setting any of those properties. Internally, backends still apply properties sequentially. The behaviour should be exactly the same as before. Future commits will update some backends to take advantage of the atomic interface. Some backends are non-atomic by design, e.g. the X11 backend or the legacy DRM backend. Updates: https://github.com/swaywm/wlroots/issues/1640
This commit is contained in:
parent
d20aee6c9d
commit
ee5f98ad49
10 changed files with 291 additions and 114 deletions
|
|
@ -154,38 +154,50 @@ static void output_update_matrix(struct wlr_output *output) {
|
|||
output->height, output->transform);
|
||||
}
|
||||
|
||||
bool wlr_output_enable(struct wlr_output *output, bool enable) {
|
||||
void wlr_output_enable(struct wlr_output *output, bool enable) {
|
||||
if (output->enabled == enable) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (output->impl->enable) {
|
||||
return output->impl->enable(output, enable);
|
||||
}
|
||||
return false;
|
||||
output->pending.committed |= WLR_OUTPUT_STATE_ENABLED;
|
||||
output->pending.enabled = enable;
|
||||
}
|
||||
|
||||
bool wlr_output_set_mode(struct wlr_output *output,
|
||||
static void output_state_clear_mode(struct wlr_output_state *state) {
|
||||
if (!(state->committed & WLR_OUTPUT_STATE_MODE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
state->mode = NULL;
|
||||
|
||||
state->committed &= ~WLR_OUTPUT_STATE_MODE;
|
||||
}
|
||||
|
||||
void wlr_output_set_mode(struct wlr_output *output,
|
||||
struct wlr_output_mode *mode) {
|
||||
if (!output->impl || !output->impl->set_mode) {
|
||||
return false;
|
||||
}
|
||||
if (output->current_mode == mode) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
return output->impl->set_mode(output, mode);
|
||||
|
||||
output_state_clear_mode(&output->pending);
|
||||
output->pending.committed |= WLR_OUTPUT_STATE_MODE;
|
||||
output->pending.mode_type = WLR_OUTPUT_STATE_MODE_FIXED;
|
||||
output->pending.mode = mode;
|
||||
}
|
||||
|
||||
bool wlr_output_set_custom_mode(struct wlr_output *output, int32_t width,
|
||||
void wlr_output_set_custom_mode(struct wlr_output *output, int32_t width,
|
||||
int32_t height, int32_t refresh) {
|
||||
if (!output->impl || !output->impl->set_custom_mode) {
|
||||
return false;
|
||||
}
|
||||
if (output->width == width && output->height == height &&
|
||||
output->refresh == refresh) {
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
return output->impl->set_custom_mode(output, width, height, refresh);
|
||||
|
||||
output_state_clear_mode(&output->pending);
|
||||
output->pending.committed |= WLR_OUTPUT_STATE_MODE;
|
||||
output->pending.mode_type = WLR_OUTPUT_STATE_MODE_CUSTOM;
|
||||
output->pending.custom_mode.width = width;
|
||||
output->pending.custom_mode.height = height;
|
||||
output->pending.custom_mode.refresh = refresh;
|
||||
}
|
||||
|
||||
void wlr_output_update_mode(struct wlr_output *output,
|
||||
|
|
@ -227,16 +239,8 @@ void wlr_output_set_transform(struct wlr_output *output,
|
|||
return;
|
||||
}
|
||||
|
||||
output->transform = transform;
|
||||
output_update_matrix(output);
|
||||
|
||||
struct wl_resource *resource;
|
||||
wl_resource_for_each(resource, &output->resources) {
|
||||
send_geometry(resource);
|
||||
}
|
||||
wlr_output_schedule_done(output);
|
||||
|
||||
wlr_signal_emit_safe(&output->events.transform, output);
|
||||
output->pending.committed |= WLR_OUTPUT_STATE_TRANSFORM;
|
||||
output->pending.transform = transform;
|
||||
}
|
||||
|
||||
void wlr_output_set_scale(struct wlr_output *output, float scale) {
|
||||
|
|
@ -244,15 +248,8 @@ void wlr_output_set_scale(struct wlr_output *output, float scale) {
|
|||
return;
|
||||
}
|
||||
|
||||
output->scale = scale;
|
||||
|
||||
struct wl_resource *resource;
|
||||
wl_resource_for_each(resource, &output->resources) {
|
||||
send_scale(resource);
|
||||
}
|
||||
wlr_output_schedule_done(output);
|
||||
|
||||
wlr_signal_emit_safe(&output->events.scale, output);
|
||||
output->pending.committed |= WLR_OUTPUT_STATE_SCALE;
|
||||
output->pending.scale = scale;
|
||||
}
|
||||
|
||||
void wlr_output_set_subpixel(struct wlr_output *output,
|
||||
|
|
@ -458,18 +455,15 @@ static void output_state_clear(struct wlr_output_state *state) {
|
|||
}
|
||||
|
||||
bool wlr_output_commit(struct wlr_output *output) {
|
||||
if (output->frame_pending) {
|
||||
wlr_log(WLR_ERROR, "Tried to commit when a frame is pending");
|
||||
return false;
|
||||
}
|
||||
if (output->idle_frame != NULL) {
|
||||
wl_event_source_remove(output->idle_frame);
|
||||
output->idle_frame = NULL;
|
||||
}
|
||||
|
||||
if (!(output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) {
|
||||
wlr_log(WLR_ERROR, "Tried to commit without attaching a buffer");
|
||||
return false;
|
||||
if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
if (output->frame_pending) {
|
||||
wlr_log(WLR_ERROR, "Tried to commit a buffer while a frame is pending");
|
||||
return false;
|
||||
}
|
||||
if (output->idle_frame != NULL) {
|
||||
wl_event_source_remove(output->idle_frame);
|
||||
output->idle_frame = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct timespec now;
|
||||
|
|
@ -486,20 +480,52 @@ bool wlr_output_commit(struct wlr_output *output) {
|
|||
return false;
|
||||
}
|
||||
|
||||
struct wlr_output_cursor *cursor;
|
||||
wl_list_for_each(cursor, &output->cursors, link) {
|
||||
if (!cursor->enabled || !cursor->visible || cursor->surface == NULL) {
|
||||
continue;
|
||||
if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
struct wlr_output_cursor *cursor;
|
||||
wl_list_for_each(cursor, &output->cursors, link) {
|
||||
if (!cursor->enabled || !cursor->visible || cursor->surface == NULL) {
|
||||
continue;
|
||||
}
|
||||
wlr_surface_send_frame_done(cursor->surface, &now);
|
||||
}
|
||||
wlr_surface_send_frame_done(cursor->surface, &now);
|
||||
}
|
||||
|
||||
wlr_signal_emit_safe(&output->events.commit, output);
|
||||
|
||||
output->frame_pending = true;
|
||||
output->needs_frame = false;
|
||||
bool scale_updated = output->pending.committed & WLR_OUTPUT_STATE_SCALE;
|
||||
if (scale_updated) {
|
||||
output->scale = output->pending.scale;
|
||||
wlr_signal_emit_safe(&output->events.scale, output);
|
||||
}
|
||||
|
||||
if (output->pending.committed & WLR_OUTPUT_STATE_TRANSFORM) {
|
||||
output->transform = output->pending.transform;
|
||||
output_update_matrix(output);
|
||||
wlr_signal_emit_safe(&output->events.transform, output);
|
||||
}
|
||||
|
||||
bool geometry_updated = output->pending.committed &
|
||||
(WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM);
|
||||
if (geometry_updated || scale_updated) {
|
||||
struct wl_resource *resource;
|
||||
wl_resource_for_each(resource, &output->resources) {
|
||||
if (geometry_updated) {
|
||||
send_geometry(resource);
|
||||
}
|
||||
if (scale_updated) {
|
||||
send_scale(resource);
|
||||
}
|
||||
}
|
||||
wlr_output_schedule_done(output);
|
||||
}
|
||||
|
||||
if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
output->frame_pending = true;
|
||||
output->needs_frame = false;
|
||||
pixman_region32_clear(&output->damage);
|
||||
}
|
||||
|
||||
output_state_clear(&output->pending);
|
||||
pixman_region32_clear(&output->damage);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue