From 971cbeaa19693a586e0204b236c3c55ec82be8cd Mon Sep 17 00:00:00 2001 From: random human Date: Mon, 24 Sep 2018 20:22:52 +0530 Subject: [PATCH 1/6] wlr_surface: fix surface damage transformation Damage tracking on transformed surfaces now work (see "weston-simple-damage --rotation=90"), using either of buffer or surface damage. --- rootston/output.c | 3 +-- types/wlr_surface.c | 8 +++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rootston/output.c b/rootston/output.c index 4207f0d0..6a6b25c4 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -696,8 +696,7 @@ static void damage_from_surface(struct wlr_surface *surface, int sx, int sy, int center_x = box.x + box.width/2; int center_y = box.y + box.height/2; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); + enum wl_output_transform transform = surface->current.transform; pixman_region32_t damage; pixman_region32_init(&damage); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index ab1dfc2d..790db675 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include "util/signal.h" @@ -198,7 +199,8 @@ static void surface_update_damage(pixman_region32_t *buffer_damage, pixman_region32_init(&surface_damage); pixman_region32_copy(&surface_damage, ¤t->surface_damage); wlr_region_transform(&surface_damage, &surface_damage, - current->transform, current->buffer_width, current->buffer_height); + wlr_output_transform_invert(current->transform), + current->width, current->height); wlr_region_scale(&surface_damage, &surface_damage, current->scale); pixman_region32_union(buffer_damage, buffer_damage, &surface_damage); pixman_region32_fini(&surface_damage); @@ -307,8 +309,8 @@ static void surface_apply_damage(struct wlr_surface *surface) { pixman_region32_init(&surface_damage); pixman_region32_copy(&surface_damage, &surface->current.surface_damage); wlr_region_transform(&surface_damage, &surface_damage, - surface->current.transform, - surface->current.buffer_width, surface->current.buffer_height); + wlr_output_transform_invert(surface->current.transform), + surface->current.width, surface->current.height); wlr_region_scale(&surface_damage, &surface_damage, surface->current.scale); pixman_region32_union(&damage, &damage, &surface_damage); From 3fd5da58a0e2279e71431ca411d7a862e2f1157d Mon Sep 17 00:00:00 2001 From: random human Date: Tue, 25 Sep 2018 00:49:18 +0530 Subject: [PATCH 2/6] wlr_surface: fix surface damage on resize Instead of damaging the buffer, damage only the surface on surface (not buffer) resize. --- types/wlr_surface.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 790db675..10e0520b 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -173,8 +173,11 @@ static void surface_update_damage(pixman_region32_t *buffer_damage, struct wlr_surface_state *previous, struct wlr_surface_state *current) { pixman_region32_clear(buffer_damage); - if (current->buffer_width != previous->buffer_width || - current->buffer_height != previous->buffer_height || + pixman_region32_t surface_damage; + pixman_region32_init(&surface_damage); + + if (current->width != previous->width || + current->height != previous->height || current->dx != 0 || current->dy != 0) { // Damage the whole surface on resize or move int prev_x = -current->dx; @@ -185,26 +188,23 @@ static void surface_update_damage(pixman_region32_t *buffer_damage, prev_y = tmp; } - pixman_region32_union_rect(buffer_damage, buffer_damage, - prev_x * previous->scale, prev_y * previous->scale, - previous->buffer_width, previous->buffer_height); - pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0, - current->buffer_width, current->buffer_height); + pixman_region32_union_rect(&surface_damage, &surface_damage, prev_x, + prev_y, previous->width, previous->height); + pixman_region32_union_rect(&surface_damage, &surface_damage, 0, 0, + current->width, current->height); } else { // Copy over surface damage + buffer damage pixman_region32_union(buffer_damage, buffer_damage, ¤t->buffer_damage); - - pixman_region32_t surface_damage; - pixman_region32_init(&surface_damage); pixman_region32_copy(&surface_damage, ¤t->surface_damage); - wlr_region_transform(&surface_damage, &surface_damage, - wlr_output_transform_invert(current->transform), - current->width, current->height); - wlr_region_scale(&surface_damage, &surface_damage, current->scale); - pixman_region32_union(buffer_damage, buffer_damage, &surface_damage); - pixman_region32_fini(&surface_damage); } + + wlr_region_transform(&surface_damage, &surface_damage, + wlr_output_transform_invert(current->transform), + current->width, current->height); + wlr_region_scale(&surface_damage, &surface_damage, current->scale); + pixman_region32_union(buffer_damage, buffer_damage, &surface_damage); + pixman_region32_fini(&surface_damage); } static void surface_state_copy(struct wlr_surface_state *state, From 5eca5d8946cac22ee570cb889e137f29edffa336 Mon Sep 17 00:00:00 2001 From: random human Date: Tue, 25 Sep 2018 01:38:09 +0530 Subject: [PATCH 3/6] wlr_surface: remove duplicated damage calculation The damage is already calculated and stored in surface->buffer_damage by surface_update_damage(). --- types/wlr_surface.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 10e0520b..dde035fb 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -301,29 +301,8 @@ static void surface_apply_damage(struct wlr_surface *surface) { } if (surface->buffer != NULL && surface->buffer->released) { - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->current.buffer_damage); - - pixman_region32_t surface_damage; - pixman_region32_init(&surface_damage); - pixman_region32_copy(&surface_damage, &surface->current.surface_damage); - wlr_region_transform(&surface_damage, &surface_damage, - wlr_output_transform_invert(surface->current.transform), - surface->current.width, surface->current.height); - wlr_region_scale(&surface_damage, &surface_damage, - surface->current.scale); - pixman_region32_union(&damage, &damage, &surface_damage); - pixman_region32_fini(&surface_damage); - - pixman_region32_intersect_rect(&damage, &damage, 0, 0, - surface->current.buffer_width, surface->current.buffer_height); - struct wlr_buffer *updated_buffer = - wlr_buffer_apply_damage(surface->buffer, resource, &damage); - - pixman_region32_fini(&damage); - + wlr_buffer_apply_damage(surface->buffer, resource, &surface->buffer_damage); if (updated_buffer != NULL) { surface->buffer = updated_buffer; return; From 84ecfb546bdb2e5b21907d1ef62f6aa7477ff094 Mon Sep 17 00:00:00 2001 From: random human Date: Tue, 25 Sep 2018 02:06:02 +0530 Subject: [PATCH 4/6] wlr_surface: more consistent argument naming in surface_update_damage --- types/wlr_surface.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/types/wlr_surface.c b/types/wlr_surface.c index dde035fb..3cbac85a 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -170,39 +170,39 @@ static void surface_state_finalize(struct wlr_surface *surface, } static void surface_update_damage(pixman_region32_t *buffer_damage, - struct wlr_surface_state *previous, struct wlr_surface_state *current) { + struct wlr_surface_state *current, struct wlr_surface_state *pending) { pixman_region32_clear(buffer_damage); pixman_region32_t surface_damage; pixman_region32_init(&surface_damage); - if (current->width != previous->width || - current->height != previous->height || - current->dx != 0 || current->dy != 0) { + if (pending->width != current->width || + pending->height != current->height || + pending->dx != 0 || pending->dy != 0) { // Damage the whole surface on resize or move - int prev_x = -current->dx; - int prev_y = -current->dy; - if ((previous->transform & WL_OUTPUT_TRANSFORM_90) != 0) { + int prev_x = -pending->dx; + int prev_y = -pending->dy; + if ((current->transform & WL_OUTPUT_TRANSFORM_90) != 0) { int tmp = prev_x; prev_x = prev_y; prev_y = tmp; } pixman_region32_union_rect(&surface_damage, &surface_damage, prev_x, - prev_y, previous->width, previous->height); + prev_y, current->width, current->height); pixman_region32_union_rect(&surface_damage, &surface_damage, 0, 0, - current->width, current->height); + pending->width, pending->height); } else { // Copy over surface damage + buffer damage pixman_region32_union(buffer_damage, buffer_damage, - ¤t->buffer_damage); - pixman_region32_copy(&surface_damage, ¤t->surface_damage); + &pending->buffer_damage); + pixman_region32_copy(&surface_damage, &pending->surface_damage); } wlr_region_transform(&surface_damage, &surface_damage, - wlr_output_transform_invert(current->transform), - current->width, current->height); - wlr_region_scale(&surface_damage, &surface_damage, current->scale); + wlr_output_transform_invert(pending->transform), + pending->width, pending->height); + wlr_region_scale(&surface_damage, &surface_damage, pending->scale); pixman_region32_union(buffer_damage, buffer_damage, &surface_damage); pixman_region32_fini(&surface_damage); } From 3e0a0f3c3acef811bc355af766b2a46c625fecd2 Mon Sep 17 00:00:00 2001 From: random human Date: Thu, 4 Oct 2018 02:01:04 +0530 Subject: [PATCH 5/6] wlr_surface: add wlr_surface_get_effective_damage This calculates and returns the effective damage of the surface in surface coordinates, including the client damage (in buffer coordinates), and damage induced by resize or move events. --- include/wlr/types/wlr_surface.h | 8 ++++ rootston/output.c | 7 +--- types/wlr_surface.c | 71 +++++++++++++++++++++------------ 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 063f9e26..ef789b82 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -229,4 +229,12 @@ struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource); void wlr_surface_for_each_surface(struct wlr_surface *surface, wlr_surface_iterator_func_t iterator, void *user_data); +/** + * Get the effective damage to the surface in terms of surface local + * coordinates. This includes damage induced by resizing and moving the + * surface. The damage is not expected to be bounded by the surface itself. + */ +void wlr_surface_get_effective_damage(struct wlr_surface *surface, + pixman_region32_t *damage); + #endif diff --git a/rootston/output.c b/rootston/output.c index 6a6b25c4..d7c5d821 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -696,13 +696,10 @@ static void damage_from_surface(struct wlr_surface *surface, int sx, int sy, int center_x = box.x + box.width/2; int center_y = box.y + box.height/2; - enum wl_output_transform transform = surface->current.transform; - pixman_region32_t damage; pixman_region32_init(&damage); - pixman_region32_copy(&damage, &surface->buffer_damage); - wlr_region_transform(&damage, &damage, transform, - surface->current.buffer_width, surface->current.buffer_height); + wlr_surface_get_effective_damage(surface, &damage); + wlr_region_scale(&damage, &damage, wlr_output->scale / (float)surface->current.scale); if (ceil(wlr_output->scale) > surface->current.scale) { diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 3cbac85a..4eb643ba 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -173,38 +173,28 @@ static void surface_update_damage(pixman_region32_t *buffer_damage, struct wlr_surface_state *current, struct wlr_surface_state *pending) { pixman_region32_clear(buffer_damage); - pixman_region32_t surface_damage; - pixman_region32_init(&surface_damage); - if (pending->width != current->width || - pending->height != current->height || - pending->dx != 0 || pending->dy != 0) { - // Damage the whole surface on resize or move - int prev_x = -pending->dx; - int prev_y = -pending->dy; - if ((current->transform & WL_OUTPUT_TRANSFORM_90) != 0) { - int tmp = prev_x; - prev_x = prev_y; - prev_y = tmp; - } - - pixman_region32_union_rect(&surface_damage, &surface_damage, prev_x, - prev_y, current->width, current->height); - pixman_region32_union_rect(&surface_damage, &surface_damage, 0, 0, - pending->width, pending->height); + pending->height != current->height) { + // Damage the whole buffer on resize + pixman_region32_union_rect(buffer_damage, buffer_damage, 0, 0, + pending->buffer_width, pending->buffer_height); } else { // Copy over surface damage + buffer damage + pixman_region32_t surface_damage; + pixman_region32_init(&surface_damage); + pixman_region32_union(buffer_damage, buffer_damage, &pending->buffer_damage); pixman_region32_copy(&surface_damage, &pending->surface_damage); - } - wlr_region_transform(&surface_damage, &surface_damage, - wlr_output_transform_invert(pending->transform), - pending->width, pending->height); - wlr_region_scale(&surface_damage, &surface_damage, pending->scale); - pixman_region32_union(buffer_damage, buffer_damage, &surface_damage); - pixman_region32_fini(&surface_damage); + wlr_region_transform(&surface_damage, &surface_damage, + wlr_output_transform_invert(pending->transform), + pending->width, pending->height); + wlr_region_scale(&surface_damage, &surface_damage, pending->scale); + + pixman_region32_union(buffer_damage, buffer_damage, &surface_damage); + pixman_region32_fini(&surface_damage); + } } static void surface_state_copy(struct wlr_surface_state *state, @@ -1030,3 +1020,34 @@ void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box) { box->width = acc.max_x - acc.min_x; box->height = acc.max_y - acc.min_y; } + +void wlr_surface_get_effective_damage(struct wlr_surface *surface, + pixman_region32_t *damage) { + pixman_region32_clear(damage); + + // Transform and copy the buffer damage in terms of surface coordinates. + wlr_region_transform(damage, &surface->buffer_damage, + surface->current.transform, surface->current.buffer_width, + surface->current.buffer_height); + + // On resize, damage the previous bounds of the surface. The current bounds + // have already been damaged in surface_update_damage. + if (surface->previous.width > surface->current.width || + surface->previous.height > surface->current.height) { + pixman_region32_union_rect(damage, damage, 0, 0, + surface->previous.width, surface->previous.height); + } + + // On move, damage where the surface was with its old dimensions. + if (surface->current.dx != 0 || surface->current.dy != 0) { + int prev_x = -surface->current.dx; + int prev_y = -surface->current.dy; + if ((surface->previous.transform & WL_OUTPUT_TRANSFORM_90) != 0) { + int temp = prev_x; + prev_x = prev_y; + prev_y = temp; + } + pixman_region32_union_rect(damage, damage, prev_x, prev_y, + surface->previous.width, surface->previous.height); + } +} From dec303bea6bdc31941c32074286521b742f932d4 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 4 Nov 2018 11:08:06 +0100 Subject: [PATCH 6/6] surface: fix wlr_surface_get_effective_damage to give surface coords Transforms were applied, but scale wasn't. --- include/wlr/types/wlr_surface.h | 25 +++++++++++++------------ rootston/output.c | 3 +-- types/wlr_surface.c | 12 ++++++------ 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index ef789b82..6177e059 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -17,14 +17,14 @@ #include enum wlr_surface_state_field { - WLR_SURFACE_STATE_BUFFER = 1, - WLR_SURFACE_STATE_SURFACE_DAMAGE = 2, - WLR_SURFACE_STATE_BUFFER_DAMAGE = 4, - WLR_SURFACE_STATE_OPAQUE_REGION = 8, - WLR_SURFACE_STATE_INPUT_REGION = 16, - WLR_SURFACE_STATE_TRANSFORM = 32, - WLR_SURFACE_STATE_SCALE = 64, - WLR_SURFACE_STATE_FRAME_CALLBACK_LIST = 128, + WLR_SURFACE_STATE_BUFFER = 1 << 0, + WLR_SURFACE_STATE_SURFACE_DAMAGE = 1 << 1, + WLR_SURFACE_STATE_BUFFER_DAMAGE = 1 << 2, + WLR_SURFACE_STATE_OPAQUE_REGION = 1 << 3, + WLR_SURFACE_STATE_INPUT_REGION = 1 << 4, + WLR_SURFACE_STATE_TRANSFORM = 1 << 5, + WLR_SURFACE_STATE_SCALE = 1 << 6, + WLR_SURFACE_STATE_FRAME_CALLBACK_LIST = 1 << 7, }; struct wlr_surface_state { @@ -32,7 +32,7 @@ struct wlr_surface_state { struct wl_resource *buffer_resource; int32_t dx, dy; // relative to previous position - pixman_region32_t surface_damage, buffer_damage; + pixman_region32_t surface_damage, buffer_damage; // clipped to bounds pixman_region32_t opaque, input; enum wl_output_transform transform; int32_t scale; @@ -68,11 +68,12 @@ struct wlr_surface { * The last commit's buffer damage, in buffer-local coordinates. This * contains both the damage accumulated by the client via * `wlr_surface_state.surface_damage` and `wlr_surface_state.buffer_damage`. - * If the buffer has changed its size or moved, the whole buffer is - * damaged. + * If the buffer has been resized, the whole buffer is damaged. * * This region needs to be scaled and transformed into output coordinates, - * just like the buffer's texture. + * just like the buffer's texture. In addition, if the buffer has shrunk the + * old size needs to be damaged and if the buffer has moved the old and new + * positions need to be damaged. */ pixman_region32_t buffer_damage; /** diff --git a/rootston/output.c b/rootston/output.c index d7c5d821..674cda2d 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -700,8 +700,7 @@ static void damage_from_surface(struct wlr_surface *surface, int sx, int sy, pixman_region32_init(&damage); wlr_surface_get_effective_damage(surface, &damage); - wlr_region_scale(&damage, &damage, - wlr_output->scale / (float)surface->current.scale); + wlr_region_scale(&damage, &damage, wlr_output->scale); if (ceil(wlr_output->scale) > surface->current.scale) { // When scaling up a surface, it'll become blurry so we need to // expand the damage region diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 4eb643ba..12931dad 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -183,16 +183,15 @@ static void surface_update_damage(pixman_region32_t *buffer_damage, pixman_region32_t surface_damage; pixman_region32_init(&surface_damage); - pixman_region32_union(buffer_damage, buffer_damage, - &pending->buffer_damage); pixman_region32_copy(&surface_damage, &pending->surface_damage); - wlr_region_transform(&surface_damage, &surface_damage, wlr_output_transform_invert(pending->transform), pending->width, pending->height); wlr_region_scale(&surface_damage, &surface_damage, pending->scale); - pixman_region32_union(buffer_damage, buffer_damage, &surface_damage); + pixman_region32_union(buffer_damage, + &pending->buffer_damage, &surface_damage); + pixman_region32_fini(&surface_damage); } } @@ -291,8 +290,8 @@ static void surface_apply_damage(struct wlr_surface *surface) { } if (surface->buffer != NULL && surface->buffer->released) { - struct wlr_buffer *updated_buffer = - wlr_buffer_apply_damage(surface->buffer, resource, &surface->buffer_damage); + struct wlr_buffer *updated_buffer = wlr_buffer_apply_damage( + surface->buffer, resource, &surface->buffer_damage); if (updated_buffer != NULL) { surface->buffer = updated_buffer; return; @@ -1029,6 +1028,7 @@ void wlr_surface_get_effective_damage(struct wlr_surface *surface, wlr_region_transform(damage, &surface->buffer_damage, surface->current.transform, surface->current.buffer_width, surface->current.buffer_height); + wlr_region_scale(damage, damage, 1.0 / (float)surface->current.scale); // On resize, damage the previous bounds of the surface. The current bounds // have already been damaged in surface_update_damage.