core: move damage ring related fields in session_t into a separate struct

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-03-24 03:22:58 +00:00
parent 0e9e0688b8
commit d3c2e01fb0
No known key found for this signature in database
GPG Key ID: D3A4405BE6CC17F4
5 changed files with 66 additions and 64 deletions

View File

@ -42,17 +42,7 @@ region_t get_damage(session_t *ps, bool all_damage) {
}
pixman_region32_init(&region);
if (buffer_age == -1 || buffer_age > ps->ndamage) {
pixman_region32_copy(&region, &ps->screen_reg);
} else {
for (int i = 0; i < buffer_age; i++) {
auto curr = ((ps->damage - ps->damage_ring) + i) % ps->ndamage;
log_trace("damage index: %d, damage ring offset: %td", i, curr);
dump_region(&ps->damage_ring[curr]);
pixman_region32_union(&region, &region, &ps->damage_ring[curr]);
}
pixman_region32_intersect(&region, &region, &ps->screen_reg);
}
damage_ring_collect(&ps->damage_ring, &ps->screen_reg, &region, buffer_age);
return region;
}
@ -529,11 +519,7 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
}
// Move the head of the damage ring
ps->damage = ps->damage - 1;
if (ps->damage < ps->damage_ring) {
ps->damage = ps->damage_ring + ps->ndamage - 1;
}
pixman_region32_clear(ps->damage);
damage_ring_advance(&ps->damage_ring);
if (ps->backend_data->ops->present) {
// Present the rendered scene

View File

@ -134,6 +134,18 @@ struct shader_info {
UT_hash_handle hh;
};
struct damage_ring {
/// Cache a xfixes region so we don't need to allocate it every time.
/// A workaround for yshui/picom#301
xcb_xfixes_region_t x_region;
/// The region needs to painted on next paint.
int cursor;
/// The region damaged on the last paint.
region_t *damages;
/// Number of damage regions we track
int count;
};
/// Structure containing all necessary data for a session.
typedef struct session {
// === Event handlers ===
@ -250,16 +262,8 @@ typedef struct session {
/// to the screen that's neither included in the current render, nor on the
/// screen.
bool render_queued;
/// Cache a xfixes region so we don't need to allocate it every time.
/// A workaround for yshui/picom#301
xcb_xfixes_region_t damaged_region;
/// The region needs to painted on next paint.
region_t *damage;
/// The region damaged on the last paint.
region_t *damage_ring;
/// Number of damage regions we track
int ndamage;
/// For tracking damage regions
struct damage_ring damage_ring;
/// Whether all windows are currently redirected.
bool redirected;
/// Pre-generated alpha pictures.
@ -518,3 +522,24 @@ static inline void wintype_arr_enable(bool arr[]) {
arr[i] = true;
}
}
static inline void damage_ring_advance(struct damage_ring *ring) {
ring->cursor--;
if (ring->cursor < 0) {
ring->cursor += ring->count;
}
pixman_region32_clear(&ring->damages[ring->cursor]);
}
static inline void damage_ring_collect(struct damage_ring *ring, region_t *all_region,
region_t *region, int buffer_age) {
if (buffer_age == -1 || buffer_age > ring->count) {
pixman_region32_copy(region, all_region);
} else {
for (int i = 0; i < buffer_age; i++) {
auto curr = (ring->cursor + i) % ring->count;
pixman_region32_union(region, region, &ring->damages[curr]);
}
pixman_region32_intersect(region, region, all_region);
}
}

View File

@ -629,12 +629,12 @@ static inline void repair_win(session_t *ps, struct managed_win *w) {
}
win_extents(w, &parts);
} else {
auto cookie =
xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE, ps->damaged_region);
auto cookie = xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE,
ps->damage_ring.x_region);
if (!ps->o.show_all_xerrors) {
set_ignore_cookie(&ps->c, cookie);
}
x_fetch_region(&ps->c, ps->damaged_region, &parts);
x_fetch_region(&ps->c, ps->damage_ring.x_region, &parts);
pixman_region32_translate(&parts, w->g.x + w->g.border_width,
w->g.y + w->g.border_width);
}

View File

@ -464,7 +464,9 @@ void add_damage(session_t *ps, const region_t *damage) {
}
log_trace("Adding damage: ");
dump_region(damage);
pixman_region32_union(ps->damage, ps->damage, (region_t *)damage);
auto cursor = &ps->damage_ring.damages[ps->damage_ring.cursor];
pixman_region32_union(cursor, cursor, (region_t *)damage);
}
// === Fading ===
@ -853,10 +855,10 @@ static void configure_root(session_t *ps) {
}
if (ps->redirected) {
for (int i = 0; i < ps->ndamage; i++) {
pixman_region32_clear(&ps->damage_ring[i]);
for (int i = 0; i < ps->damage_ring.count; i++) {
pixman_region32_clear(&ps->damage_ring.damages[i]);
}
ps->damage = ps->damage_ring + ps->ndamage - 1;
ps->damage_ring.cursor = ps->damage_ring.count - 1;
#ifdef CONFIG_OPENGL
// GLX root change callback
if (BKEND_GLX == ps->o.backend && ps->o.legacy_backends) {
@ -1531,15 +1533,15 @@ static bool redirect_start(session_t *ps) {
if (!ps->o.legacy_backends) {
assert(ps->backend_data);
ps->ndamage = ps->backend_data->ops->max_buffer_age;
ps->damage_ring.count = ps->backend_data->ops->max_buffer_age;
} else {
ps->ndamage = maximum_buffer_age(ps);
ps->damage_ring.count = maximum_buffer_age(ps);
}
ps->damage_ring = ccalloc(ps->ndamage, region_t);
ps->damage = ps->damage_ring + ps->ndamage - 1;
ps->damage_ring.damages = ccalloc(ps->damage_ring.count, region_t);
ps->damage_ring.cursor = ps->damage_ring.count - 1;
for (int i = 0; i < ps->ndamage; i++) {
pixman_region32_init(&ps->damage_ring[i]);
for (int i = 0; i < ps->damage_ring.count; i++) {
pixman_region32_init(&ps->damage_ring.damages[i]);
}
ps->frame_pacing = !ps->o.no_frame_pacing && ps->o.vsync;
@ -1613,12 +1615,13 @@ static void unredirect(session_t *ps) {
}
// Free the damage ring
for (int i = 0; i < ps->ndamage; ++i) {
pixman_region32_fini(&ps->damage_ring[i]);
for (int i = 0; i < ps->damage_ring.count; ++i) {
pixman_region32_fini(&ps->damage_ring.damages[i]);
}
ps->ndamage = 0;
free(ps->damage_ring);
ps->damage_ring = ps->damage = NULL;
ps->damage_ring.count = 0;
free(ps->damage_ring.damages);
ps->damage_ring.cursor = 0;
ps->damage_ring.damages = NULL;
if (ps->vblank_scheduler) {
vblank_scheduler_free(ps->vblank_scheduler);
@ -2209,8 +2212,9 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
XCB_XFIXES_MINOR_VERSION)
.sequence);
ps->damaged_region = x_new_id(&ps->c);
if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c.c, ps->damaged_region, 0, NULL)) {
ps->damage_ring.x_region = x_new_id(&ps->c);
if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c.c, ps->damage_ring.x_region,
0, NULL)) {
log_fatal("Failed to create a XFixes region");
goto err;
}
@ -2706,9 +2710,9 @@ static void session_destroy(session_t *ps) {
ps->debug_window = XCB_NONE;
}
if (ps->damaged_region != XCB_NONE) {
xcb_xfixes_destroy_region(ps->c.c, ps->damaged_region);
ps->damaged_region = XCB_NONE;
if (ps->damage_ring.x_region != XCB_NONE) {
xcb_xfixes_destroy_region(ps->c.c, ps->damage_ring.x_region);
ps->damage_ring.x_region = XCB_NONE;
}
if (!ps->o.legacy_backends) {

View File

@ -1009,16 +1009,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
region_t region;
pixman_region32_init(&region);
int buffer_age = get_buffer_age(ps);
if (buffer_age == -1 || buffer_age > ps->ndamage) {
pixman_region32_copy(&region, &ps->screen_reg);
} else {
for (int i = 0; i < get_buffer_age(ps); i++) {
auto curr = ((ps->damage - ps->damage_ring) + i) % ps->ndamage;
pixman_region32_union(&region, &region, &ps->damage_ring[curr]);
}
}
damage_ring_collect(&ps->damage_ring, &ps->screen_reg, &region, get_buffer_age(ps));
if (!pixman_region32_not_empty(&region)) {
return;
}
@ -1219,11 +1210,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
pixman_region32_fini(&reg_shadow_clip);
// Move the head of the damage ring
ps->damage = ps->damage - 1;
if (ps->damage < ps->damage_ring) {
ps->damage = ps->damage_ring + ps->ndamage - 1;
}
pixman_region32_clear(ps->damage);
damage_ring_advance(&ps->damage_ring);
// Do this as early as possible
set_tgt_clip(ps, &ps->screen_reg);