1
0
Fork 0
mirror of https://github.com/yshui/picom.git synced 2025-04-07 17:44:04 -04:00

region: fix region scaling

We claim region_scale_floor returns the largest integer region contained
by the scaling result. But in fact what it's doing is taking the floor of
each rectangle of the region separated, which leaves gaps between
rectangles. This is not what we want.

Just always take the ceil instead, hopefully the difference is small
enough to be unnoticeable.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-06-21 13:33:58 +01:00
parent 5ec2c873df
commit e068dc8a73
No known key found for this signature in database
GPG key ID: D3A4405BE6CC17F4
4 changed files with 27 additions and 37 deletions

View file

@ -360,7 +360,7 @@ static bool xrender_blit(struct backend_base *base, ivec2 origin,
scoped_region_t source_mask_region;
pixman_region32_init(&source_mask_region);
pixman_region32_copy(&source_mask_region, args->target_mask);
region_scale_ceil(&source_mask_region, origin, inverse_scale);
region_scale(&source_mask_region, origin, inverse_scale);
x_set_picture_clip_region(
xd->base.c, tmp_pict, to_i16_checked(-origin.x),
to_i16_checked(-origin.y), &source_mask_region);

View file

@ -162,39 +162,29 @@ static inline void region_intersect(region_t *region, ivec2 origin, const region
pixman_region32_translate(region, origin.x, origin.y);
}
#define define_region_scale(suffix, lower_bound, upper_bound) \
static inline void region_scale##suffix(region_t *region, ivec2 origin, vec2 scale) { \
if (vec2_eq(scale, SCALE_IDENTITY)) { \
return; \
} \
\
int n; \
region_t tmp = *region; \
auto r = pixman_region32_rectangles(&tmp, &n); \
for (int i = 0; i < n; i++) { \
r[i].x1 = to_i32_saturated( \
lower_bound((r[i].x1 - origin.x) * scale.x + origin.x)); \
r[i].y1 = to_i32_saturated( \
lower_bound((r[i].y1 - origin.y) * scale.y + origin.y)); \
r[i].x2 = to_i32_saturated( \
upper_bound((r[i].x2 - origin.x) * scale.x + origin.x)); \
r[i].y2 = to_i32_saturated( \
upper_bound((r[i].y2 - origin.y) * scale.y + origin.y)); \
} \
\
/* Manipulating the rectangles could break assumptions made internally \
* by pixman, so we recreate the region with the rectangles to let \
* pixman fix them. */ \
pixman_region32_init_rects(region, r, n); \
pixman_region32_fini(&tmp); \
/// Scale the `region` by `scale`. The origin of scaling is `origin`. Returns the smallest
/// integer region that contains the result.
static inline void region_scale(region_t *region, ivec2 origin, vec2 scale) {
if (vec2_eq(scale, SCALE_IDENTITY)) {
return;
}
/// Scale the `region` by `scale`. The origin of scaling is `origin`. Returns the largest integer
/// region that is contained in the result.
define_region_scale(_floor, ceil, floor);
/// Scale the `region` by `scale`. The origin of scaling is `origin`. Returns the smallest integer
/// region that contains the result.
define_region_scale(_ceil, floor, ceil);
int n;
region_t tmp = *region;
auto r = pixman_region32_rectangles(&tmp, &n);
for (int i = 0; i < n; i++) {
r[i].x1 = to_i32_saturated(floor((r[i].x1 - origin.x) * scale.x + origin.x));
r[i].y1 = to_i32_saturated(floor((r[i].y1 - origin.y) * scale.y + origin.y));
r[i].x2 = to_i32_saturated(ceil((r[i].x2 - origin.x) * scale.x + origin.x));
r[i].y2 = to_i32_saturated(ceil((r[i].y2 - origin.y) * scale.y + origin.y));
}
/* Manipulating the rectangles could break assumptions made internally
* by pixman, so we recreate the region with the rectangles to let
* pixman fix them. */
pixman_region32_init_rects(region, r, n);
pixman_region32_fini(&tmp);
}
/// Calculate the symmetric difference of `region1`, and `region2`, and union the result
/// into `result`. The two input regions has to be in the same coordinate space.

View file

@ -51,8 +51,8 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd,
if (w->corner_radius > 0) {
win_region_remove_corners(w, layer->window.origin, &cmd->opaque_region);
}
region_scale_floor(&cmd->target_mask, layer->window.origin, layer->scale);
region_scale_floor(&cmd->opaque_region, layer->window.origin, layer->scale);
region_scale(&cmd->target_mask, layer->window.origin, layer->scale);
region_scale(&cmd->opaque_region, layer->window.origin, layer->scale);
pixman_region32_intersect(&cmd->target_mask, &cmd->target_mask, &crop);
pixman_region32_intersect(&cmd->opaque_region, &cmd->opaque_region, &crop);
cmd->op = BACKEND_COMMAND_BLIT;
@ -77,7 +77,7 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd,
cmd -= 1;
pixman_region32_copy(&cmd->target_mask, frame_region);
region_scale_floor(&cmd->target_mask, cmd->origin, layer->scale);
region_scale(&cmd->target_mask, cmd->origin, layer->scale);
pixman_region32_intersect(&cmd->target_mask, &cmd->target_mask, &crop);
pixman_region32_init(&cmd->opaque_region);
cmd->op = BACKEND_COMMAND_BLIT;
@ -179,7 +179,7 @@ command_for_blur(struct layer *layer, struct backend_command *cmd,
} else {
return 0;
}
region_scale_floor(&cmd->target_mask, layer->window.origin, layer->scale);
region_scale(&cmd->target_mask, layer->window.origin, layer->scale);
scoped_region_t crop = region_from_box(layer->crop);
pixman_region32_intersect(&cmd->target_mask, &cmd->target_mask, &crop);

View file

@ -97,7 +97,7 @@ command_blit_damage(region_t *damage, region_t *scratch_region, struct backend_c
if (cmd1->source == BACKEND_COMMAND_SOURCE_WINDOW) {
layout_manager_collect_window_damage(lm, layer_index, buffer_age,
scratch_region);
region_scale_floor(scratch_region, cmd2->origin, cmd2->blit.scale);
region_scale(scratch_region, cmd2->origin, cmd2->blit.scale);
pixman_region32_intersect(scratch_region, scratch_region, &cmd1->target_mask);
pixman_region32_intersect(scratch_region, scratch_region, &cmd2->target_mask);
pixman_region32_union(damage, damage, scratch_region);