Skip to content

Commit

Permalink
region: fix region scaling
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
yshui committed Jun 21, 2024
1 parent 5ec2c87 commit e068dc8
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/backend/xrender/xrender.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
52 changes: 21 additions & 31 deletions src/region.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

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));
}

/// 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);
/* 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.
Expand Down
8 changes: 4 additions & 4 deletions src/renderer/command_builder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/damage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit e068dc8

Please sign in to comment.