diff --git a/src/compositor.c b/src/compositor.c index 8bf55dc5..9e153104 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -525,7 +525,8 @@ weston_surface_state_init(struct weston_surface_state *state) state->sx = 0; state->sy = 0; - pixman_region32_init(&state->damage); + pixman_region32_init(&state->damage_surface); + pixman_region32_init(&state->damage_buffer); pixman_region32_init(&state->opaque); region_init_infinite(&state->input); @@ -552,7 +553,8 @@ weston_surface_state_fini(struct weston_surface_state *state) pixman_region32_fini(&state->input); pixman_region32_fini(&state->opaque); - pixman_region32_fini(&state->damage); + pixman_region32_fini(&state->damage_surface); + pixman_region32_fini(&state->damage_buffer); if (state->buffer) wl_list_remove(&state->buffer_destroy_listener.link); @@ -2569,8 +2571,23 @@ surface_damage(struct wl_client *client, if (width <= 0 || height <= 0) return; - pixman_region32_union_rect(&surface->pending.damage, - &surface->pending.damage, + pixman_region32_union_rect(&surface->pending.damage_surface, + &surface->pending.damage_surface, + x, y, width, height); +} + +static void +surface_damage_buffer(struct wl_client *client, + struct wl_resource *resource, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + struct weston_surface *surface = wl_resource_get_user_data(resource); + + if (width <= 0 || height <= 0) + return; + + pixman_region32_union_rect(&surface->pending.damage_buffer, + &surface->pending.damage_buffer, x, y, width, height); } @@ -2733,6 +2750,40 @@ weston_surface_build_buffer_matrix(struct weston_surface *surface, weston_matrix_scale(matrix, vp->buffer.scale, vp->buffer.scale, 1); } +/* Translate pending damage in buffer co-ordinates to surface + * co-ordinates and union it with a pixman_region32_t. + * This should only be called after the buffer is attached. + */ +static void +apply_damage_buffer(pixman_region32_t *dest, + struct weston_surface *surface, + struct weston_surface_state *state) +{ + struct weston_buffer *buffer = surface->buffer_ref.buffer; + + /* wl_surface.damage_buffer needs to be clipped to the buffer, + * translated into surface co-ordinates and unioned with + * any other surface damage. + * None of this makes sense if there is no buffer though. + */ + if (buffer && pixman_region32_not_empty(&state->damage_buffer)) { + pixman_region32_t buffer_damage; + + pixman_region32_intersect_rect(&state->damage_buffer, + &state->damage_buffer, + 0, 0, buffer->width, + buffer->height); + pixman_region32_init(&buffer_damage); + weston_matrix_transform_region(&buffer_damage, + &surface->buffer_to_surface_matrix, + &state->damage_buffer); + pixman_region32_union(dest, dest, &buffer_damage); + pixman_region32_fini(&buffer_damage); + } + /* We should clear this on commit even if there was no buffer */ + pixman_region32_clear(&state->damage_buffer); +} + static void weston_surface_commit_state(struct weston_surface *surface, struct weston_surface_state *state) @@ -2766,15 +2817,20 @@ weston_surface_commit_state(struct weston_surface *surface, state->newly_attached = 0; state->buffer_viewport.changed = 0; - /* wl_surface.damage */ + /* wl_surface.damage and wl_surface.damage_buffer */ if (weston_timeline_enabled_ && - pixman_region32_not_empty(&state->damage)) + (pixman_region32_not_empty(&state->damage_surface) || + pixman_region32_not_empty(&state->damage_buffer))) TL_POINT("core_commit_damage", TLP_SURFACE(surface), TLP_END); + pixman_region32_union(&surface->damage, &surface->damage, - &state->damage); + &state->damage_surface); + + apply_damage_buffer(&surface->damage, surface, state); + pixman_region32_intersect_rect(&surface->damage, &surface->damage, 0, 0, surface->width, surface->height); - pixman_region32_clear(&state->damage); + pixman_region32_clear(&state->damage_surface); /* wl_surface.set_opaque_region */ pixman_region32_init(&opaque); @@ -2893,7 +2949,8 @@ static const struct wl_surface_interface surface_interface = { surface_set_input_region, surface_commit, surface_set_buffer_transform, - surface_set_buffer_scale + surface_set_buffer_scale, + surface_damage_buffer }; static void @@ -3022,11 +3079,12 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub) * translated to correspond to the new surface coordinate system * origin. */ - pixman_region32_translate(&sub->cached.damage, + pixman_region32_translate(&sub->cached.damage_surface, -surface->pending.sx, -surface->pending.sy); - pixman_region32_union(&sub->cached.damage, &sub->cached.damage, - &surface->pending.damage); - pixman_region32_clear(&surface->pending.damage); + pixman_region32_union(&sub->cached.damage_surface, + &sub->cached.damage_surface, + &surface->pending.damage_surface); + pixman_region32_clear(&surface->pending.damage_surface); if (surface->pending.newly_attached) { sub->cached.newly_attached = 1; @@ -3040,6 +3098,8 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub) sub->cached.sx += surface->pending.sx; sub->cached.sy += surface->pending.sy; + apply_damage_buffer(&sub->cached.damage_surface, surface, &surface->pending); + sub->cached.buffer_viewport.changed |= surface->pending.buffer_viewport.changed; sub->cached.buffer_viewport.buffer = @@ -4536,7 +4596,7 @@ weston_compositor_create(struct wl_display *display, void *user_data) ec->output_id_pool = 0; ec->repaint_msec = DEFAULT_REPAINT_WINDOW; - if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 3, + if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4, ec, compositor_bind)) goto fail; diff --git a/src/compositor.h b/src/compositor.h index 1d044818..43db92ea 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -931,7 +931,9 @@ struct weston_surface_state { int32_t sy; /* wl_surface.damage */ - pixman_region32_t damage; + pixman_region32_t damage_surface; + /* wl_surface.damage_buffer */ + pixman_region32_t damage_buffer; /* wl_surface.set_opaque_region */ pixman_region32_t opaque;