Skip to content

Commit

Permalink
renderer: fix handling of root pixmap changes
Browse files Browse the repository at this point in the history
I thought to myself, "I will add this later", then proceeded to forget
about this...

The `root_damaged` flag in `struct session` I added in anticipation for
this is actually not enough. Imagine this:

frame 0 -> frame 1 -> frame 2 (root changed) -> frame 3

frame 2 will be rendered with the `root_damaged` flag set, all good.
But `frame 3` wouldn't, and if it has buffer age 2, i.e. it's rendered
on top of the base of `frame 1`, then the result will be wrong because
frame 1 and 3 has different root background. So instead I added a
`root_image_generation` that is incremented every time the root image
changes.

Fixes #1247

Signed-off-by: Yuxuan Shui <[email protected]>
  • Loading branch information
yshui committed Apr 28, 2024
1 parent 09b5803 commit e5e618f
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 9 deletions.
5 changes: 3 additions & 2 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ typedef struct session {
paint_t root_tile_paint;
/// The backend data the root pixmap bound to
image_handle root_image;
/// The root pixmap generation, incremented everytime
/// the root pixmap changes
uint64_t root_image_generation;
/// A region of the size of the screen.
region_t screen_reg;
/// Picture of root window. Destination of painting in no-DBE painting
Expand Down Expand Up @@ -271,8 +274,6 @@ typedef struct session {
/// Render command builder
struct command_builder *command_builder;
struct renderer *renderer;
/// Whether the root image has been changed since last render
bool root_damaged;
/// Whether all windows are currently redirected.
bool redirected;
/// Pre-generated alpha pictures.
Expand Down
4 changes: 2 additions & 2 deletions src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -1189,12 +1189,12 @@ void root_damaged(session_t *ps) {

ps->root_image = ps->backend_data->ops->v2.bind_pixmap(
ps->backend_data, pixmap, x_get_visual_info(&ps->c, visual));
ps->root_image_generation += 1;
if (!ps->root_image) {
err:
log_error("Failed to bind root back pixmap");
}
}
ps->root_damaged = true;
}

// Mark screen damaged
Expand Down Expand Up @@ -1846,7 +1846,7 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) {
auto render_start_us =
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
layout_manager_append_layout(
ps->layout_manager, ps->wm,
ps->layout_manager, ps->wm, ps->root_image_generation,
(struct geometry){.width = ps->root_width,
.height = ps->root_height});
bool succeeded = renderer_render(
Expand Down
5 changes: 2 additions & 3 deletions src/renderer/damage.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,8 @@ void layout_manager_damage(struct layout_manager *lm, unsigned buffer_age,
pixman_region32_init(&scratch_region);
pixman_region32_clear(damage);
if (past_layout->size.width != curr_layout->size.width ||
past_layout->size.height != curr_layout->size.height) {
// We might be able to do better for blur size change, but currently we
// don't even support changing that.
past_layout->size.height != curr_layout->size.height ||
past_layout->root_image_generation != curr_layout->root_image_generation) {
pixman_region32_union_rect(damage, damage, 0, 0,
(unsigned)curr_layout->size.width,
(unsigned)curr_layout->size.height);
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,13 @@ void layout_manager_free(struct layout_manager *lm) {
// above.

void layout_manager_append_layout(struct layout_manager *lm, struct wm *wm,
struct geometry size) {
uint64_t root_pixmap_generation, struct geometry size) {
auto prev_layout = &lm->layouts[lm->current];
lm->current = (lm->current + 1) % lm->max_buffer_age;
auto layout = &lm->layouts[lm->current];
command_builder_command_list_free(layout->commands);
layout->root_image_generation = root_pixmap_generation;

unsigned nlayers = wm_stack_num_managed_windows(wm);
if (nlayers > layout->capacity) {
struct layer *new_layers =
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ struct layer {
/// Layout of windows at a specific frame
struct layout {
struct geometry size;
/// The root image generation, see `struct session::root_image_generation`
uint64_t root_image_generation;
/// Number of layers in `layers`
unsigned len;
/// Capacity of `layers`
Expand All @@ -96,7 +98,7 @@ struct layout_manager;
/// layouts, with its size chosen at creation time. Calling this will push at new layout
/// at the end of the ring buffer, and remove the oldest layout if the buffer is full.
void layout_manager_append_layout(struct layout_manager *lm, struct wm *wm,
struct geometry size);
uint64_t root_image_generation, struct geometry size);
/// Get the layout `age` frames into the past. Age `0` is the most recently appended
/// layout.
struct layout *layout_manager_layout(struct layout_manager *lm, unsigned age);
Expand Down

0 comments on commit e5e618f

Please sign in to comment.