render: overlay: fix visual glitches when double buffering

When rendering the overlay for scrollback search, the logic assumed
buffer re-use. On some compositors this isn’t happening (on
e.g. KDE/plasma we’re forced to double buffer).

This resulted in matches not being highlighted correctly.

The problem is in how we calculated the region for which areas to
clear ("un-dim"). It uses the "previous frame’s see-through area"
minus the current frame’s see-through area.

However, when we’ve detected that the current buffer isn’t the same as
the last one, we set the last frame’s see-through region to "the
entire buffer". Thus, when calculating the diff, we end up with an
empty region, and nothing is highlighted.

Fix by simply using the current frame’s see-through region as-is when
we’ve detected we’re not re-using the last frame’s buffer.
This commit is contained in:
Daniel Eklöf 2022-09-22 18:39:00 +02:00
parent 4340f8a3b4
commit 3be44fb316
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 22 additions and 10 deletions

View file

@ -74,6 +74,9 @@
* Glitchy rendering when scrolling in the scrollback, on compositors
that does not allow Wayland buffer re-use (e.g. KDE/plasma)
([#1173][1173])
* Scrollback search matches not being highlighted correctly, on
compositors that does now allow Wayland buffer re-use
(e.g. KDE/plasma).
[1173]: https://codeberg.org/dnkl/foot/issues/1173

View file

@ -1563,11 +1563,12 @@ render_overlay(struct terminal *term)
*/
pixman_region32_t *see_through = &term->render.last_overlay_clip;
pixman_region32_t old_see_through;
const bool buffer_reuse =
buf == term->render.last_overlay_buf &&
style == term->render.last_overlay_style &&
buf->age == 0;
if (!(buf == term->render.last_overlay_buf &&
style == term->render.last_overlay_style &&
buf->age == 0))
{
if (!buffer_reuse) {
/* Cant re-use last frames damage - set to full window,
* to ensure *everything* is updated */
pixman_region32_init_rect(
@ -1580,8 +1581,8 @@ render_overlay(struct terminal *term)
pixman_region32_clear(see_through);
/* Build region consisting of all current search matches */
struct search_match_iterator iter = search_matches_new_iter(term);
for (struct range match = search_matches_next(&iter);
match.start.row >= 0;
match = search_matches_next(&iter))
@ -1609,20 +1610,28 @@ render_overlay(struct terminal *term)
}
}
/* Current see-through, minus old see-through - aka cells that
* need to be cleared */
/* Areas that need to be cleared: cells that were dimmed in
* the last frame but is now see-through */
pixman_region32_t new_see_through;
pixman_region32_init(&new_see_through);
pixman_region32_subtract(&new_see_through, see_through, &old_see_through);
if (buffer_reuse)
pixman_region32_subtract(&new_see_through, see_through, &old_see_through);
else {
/* Buffer content is unknown - explicitly clear *all*
* current see-through areas */
pixman_region32_copy(&new_see_through, see_through);
}
pixman_image_set_clip_region32(buf->pix[0], &new_see_through);
/* Old see-through, minus new see-through - aka cells that
* needs to be dimmed */
/* Areas that need to be dimmed: cells that were cleared in
* the last frame but is not anymore */
pixman_region32_t new_dimmed;
pixman_region32_init(&new_dimmed);
pixman_region32_subtract(&new_dimmed, &old_see_through, see_through);
pixman_region32_fini(&old_see_through);
/* Total affected area */
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_union(&damage, &new_see_through, &new_dimmed);