wlr_compositor: Apply state before updating surface_damage

When locking surface state, surface_cache_pending will move the pending
surface state to a new, empty `wlr_surface_state`. This new surface
state will only contain the fields committed in the pending state, as
surface_state_move does not copy anything else.

surface_update_damage is called before we move state from pending to
current to merge buffer damage and surface damage, and it expects that
the pending surface state still contains prior committed details such as
scale and transform. This is not the case when we finally commit the
cached surface state.

Move surface_update_damage after surface_state_move and make it operate
purely on the current surface state.
This commit is contained in:
Kenny Levinsen 2026-03-28 15:02:41 +01:00
parent 334019f839
commit e5552055e9

View file

@ -246,40 +246,40 @@ static void surface_finalize_pending(struct wlr_surface *surface) {
} }
static void surface_update_damage(pixman_region32_t *buffer_damage, static void surface_update_damage(pixman_region32_t *buffer_damage,
struct wlr_surface_state *current, struct wlr_surface_state *pending) { struct wlr_surface_state *state) {
pixman_region32_clear(buffer_damage); pixman_region32_clear(buffer_damage);
// Copy over surface damage + buffer damage // Copy over surface damage + buffer damage
pixman_region32_t surface_damage; pixman_region32_t surface_damage;
pixman_region32_init(&surface_damage); pixman_region32_init(&surface_damage);
pixman_region32_copy(&surface_damage, &pending->surface_damage); pixman_region32_copy(&surface_damage, &state->surface_damage);
if (pending->viewport.has_dst) { if (state->viewport.has_dst) {
int src_width, src_height; int src_width, src_height;
surface_state_viewport_src_size(pending, &src_width, &src_height); surface_state_viewport_src_size(state, &src_width, &src_height);
float scale_x = (float)pending->viewport.dst_width / src_width; float scale_x = (float)state->viewport.dst_width / src_width;
float scale_y = (float)pending->viewport.dst_height / src_height; float scale_y = (float)state->viewport.dst_height / src_height;
wlr_region_scale_xy(&surface_damage, &surface_damage, wlr_region_scale_xy(&surface_damage, &surface_damage,
1.0 / scale_x, 1.0 / scale_y); 1.0 / scale_x, 1.0 / scale_y);
} }
if (pending->viewport.has_src) { if (state->viewport.has_src) {
// This is lossy: do a best-effort conversion // This is lossy: do a best-effort conversion
pixman_region32_translate(&surface_damage, pixman_region32_translate(&surface_damage,
floor(pending->viewport.src.x), floor(state->viewport.src.x),
floor(pending->viewport.src.y)); floor(state->viewport.src.y));
} }
wlr_region_scale(&surface_damage, &surface_damage, pending->scale); wlr_region_scale(&surface_damage, &surface_damage, state->scale);
int width, height; int width, height;
surface_state_transformed_buffer_size(pending, &width, &height); surface_state_transformed_buffer_size(state, &width, &height);
wlr_region_transform(&surface_damage, &surface_damage, wlr_region_transform(&surface_damage, &surface_damage,
wlr_output_transform_invert(pending->transform), wlr_output_transform_invert(state->transform),
width, height); width, height);
pixman_region32_union(buffer_damage, pixman_region32_union(buffer_damage,
&pending->buffer_damage, &surface_damage); &state->buffer_damage, &surface_damage);
pixman_region32_fini(&surface_damage); pixman_region32_fini(&surface_damage);
} }
@ -521,8 +521,6 @@ static void surface_commit_state(struct wlr_surface *surface,
surface->unmap_commit = false; surface->unmap_commit = false;
} }
surface_update_damage(&surface->buffer_damage, &surface->current, next);
surface->previous.scale = surface->current.scale; surface->previous.scale = surface->current.scale;
surface->previous.transform = surface->current.transform; surface->previous.transform = surface->current.transform;
surface->previous.width = surface->current.width; surface->previous.width = surface->current.width;
@ -531,6 +529,7 @@ static void surface_commit_state(struct wlr_surface *surface,
surface->previous.buffer_height = surface->current.buffer_height; surface->previous.buffer_height = surface->current.buffer_height;
surface_state_move(&surface->current, next, surface); surface_state_move(&surface->current, next, surface);
surface_update_damage(&surface->buffer_damage, &surface->current);
if (invalid_buffer) { if (invalid_buffer) {
surface_apply_damage(surface); surface_apply_damage(surface);