scene: only skip bottom-most black rects with fractional scaling

We were relying on the fact that we wouldn't paint anything on top
of the black background in the region of a black rect. However
when fractional scaling is used the repaint region might get
expanded to nearby pixels by scale_output_damage(). As a result
the neighbour scene nodes might leak into the skipped black rect's
region.

Avoid this by using this optimization for bottom-most black rects
only when fractional scaling is used.

References: https://github.com/swaywm/sway/issues/8233
This commit is contained in:
Simon Ser 2024-07-11 20:41:29 +02:00
parent f057239b6a
commit e34cc23549

View File

@ -1504,6 +1504,7 @@ struct render_list_constructor_data {
struct wl_array *render_list;
bool calculate_visibility;
bool highlight_transparent_region;
bool fractional_scale;
};
static bool construct_render_list_iterator(struct wlr_scene_node *node,
@ -1514,10 +1515,12 @@ static bool construct_render_list_iterator(struct wlr_scene_node *node,
return false;
}
// while rendering, the background should always be black.
// If we see a black rect, we can ignore rendering everything under the rect
// and even the rect itself.
if (node->type == WLR_SCENE_NODE_RECT && data->calculate_visibility) {
// While rendering, the background should always be black. If we see a
// black rect, we can ignore rendering everything under the rect, and
// unless fractional scale is used even the rect itself (to avoid running
// into issues regarding damage region expansion).
if (node->type == WLR_SCENE_NODE_RECT && data->calculate_visibility &&
(!data->fractional_scale || data->render_list->size == 0)) {
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
float *black = (float[4]){ 0.f, 0.f, 0.f, 1.f };
@ -1773,6 +1776,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
.render_list = &scene_output->render_list,
.calculate_visibility = scene_output->scene->calculate_visibility,
.highlight_transparent_region = scene_output->scene->highlight_transparent_region,
.fractional_scale = floor(render_data.scale) != render_data.scale,
};
list_con.render_list->size = 0;