Skip to content

Commit

Permalink
Make buffer age not glx specific
Browse files Browse the repository at this point in the history
Buffer age is not a glx specific concept. xrender backend can have
buffer age too, if double buffering is used (required if we want to use
Present). So, make buffer age a generic concept in compton is required
for further backend improvements.

Moved buffer age based damage aggragation out of glx as well.

Signed-off-by: Yuxuan Shui <[email protected]>
  • Loading branch information
yshui committed Jan 26, 2019
1 parent 377b18a commit e80ff85
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 285 deletions.
57 changes: 0 additions & 57 deletions src/backend/gl/glx.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,63 +592,6 @@ void glx_render_win(void *backend_data, session_t *ps, win *w, void *win_data, c
gl_check_err();
}

/**
* Preprocess function before start painting.
*/
static void attr_unused glx_paint_pre(session_t *ps, region_t *preg) {
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Get buffer age
bool trace_damage = (ps->o.glx_swap_method < 0 || ps->o.glx_swap_method > 1);

// Trace raw damage regions
region_t newdamage;
pixman_region32_init(&newdamage);
if (trace_damage)
copy_region(&newdamage, preg);

// We use GLX buffer_age extension to decide which pixels in
// the back buffer is reusable, and limit our redrawing
int buffer_age = 0;

// Query GLX_EXT_buffer_age for buffer age
if (ps->o.glx_swap_method == SWAPM_BUFFER_AGE) {
unsigned val = 0;
glXQueryDrawable(ps->dpy, get_tgt_window(ps), GLX_BACK_BUFFER_AGE_EXT, &val);
buffer_age = val;
}

// Buffer age too high
if (buffer_age > CGLX_MAX_BUFFER_AGE + 1)
buffer_age = 0;

assert(buffer_age >= 0);

if (buffer_age) {
// Determine paint area
for (int i = 0; i < buffer_age - 1; ++i)
pixman_region32_union(preg, preg, &ps->all_damage_last[i]);
} else
// buffer_age == 0 means buffer age is not available, paint everything
copy_region(preg, &ps->screen_reg);

if (trace_damage) {
// XXX use a circular queue instead of memmove
pixman_region32_fini(&ps->all_damage_last[CGLX_MAX_BUFFER_AGE - 1]);
memmove(ps->all_damage_last + 1, ps->all_damage_last,
(CGLX_MAX_BUFFER_AGE - 1) * sizeof(region_t *));
ps->all_damage_last[0] = newdamage;
}

// gl_set_clip(ps, preg);

#ifdef DEBUG_GLX_PAINTREG
glx_render_color(ps, 0, 0, ps->root_width, ps->root_height, 0, *preg, NULL);
#endif

gl_check_err();
}

backend_info_t glx_backend = {
.init = glx_init,
.deinit = glx_deinit,
Expand Down
15 changes: 4 additions & 11 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,11 @@ typedef struct session {
/// Program start time.
struct timeval time_start;
/// The region needs to painted on next paint.
region_t all_damage;
region_t *damage;
/// The region damaged on the last paint.
region_t all_damage_last[CGLX_MAX_BUFFER_AGE];
region_t *damage_ring;
/// Number of damage regions we track
int ndamage;
/// Whether all windows are currently redirected.
bool redirected;
/// Pre-generated alpha pictures.
Expand Down Expand Up @@ -897,15 +899,6 @@ find_focused(session_t *ps) {
return NULL;
}

/**
* Free all regions in ps->all_damage_last .
*/
static inline void
free_all_damage_last(session_t *ps) {
for (int i = 0; i < CGLX_MAX_BUFFER_AGE; ++i)
pixman_region32_clear(&ps->all_damage_last[i]);
}

/**
* Check if a rectangle includes the whole screen.
*/
Expand Down
72 changes: 12 additions & 60 deletions src/compton.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,38 +206,6 @@ get_time_ms(void) {
return tv.tv_sec % SEC_WRAP * 1000 + tv.tv_usec / 1000;
}

/**
* Resize a region.
*/
static inline void
resize_region(session_t *ps, region_t *region, short mod) {
if (!mod || !region) return;
// Loop through all rectangles
int nrects;
int nnewrects = 0;
pixman_box32_t *rects = pixman_region32_rectangles(region, &nrects);
auto newrects = ccalloc(nrects, pixman_box32_t);
for (int i = 0; i < nrects; i++) {
int x1 = max_i(rects[i].x1 - mod, 0);
int y1 = max_i(rects[i].y1 - mod, 0);
int x2 = min_i(rects[i].x2 + mod, ps->root_width);
int y2 = min_i(rects[i].y2 + mod, ps->root_height);
int wid = x2 - x1;
int hei = y2 - y1;
if (wid <= 0 || hei <= 0)
continue;
newrects[nnewrects] = (pixman_box32_t) {
.x1 = x1, .x2 = x2, .y1 = y1, .y2 = y2
};
++nnewrects;
}

pixman_region32_fini(region);
pixman_region32_init_rects(region, newrects, nnewrects);

free(newrects);
}

/**
* Get the Xinerama screen a window is on.
*
Expand Down Expand Up @@ -345,7 +313,7 @@ void add_damage(session_t *ps, const region_t *damage) {

if (!damage)
return;
pixman_region32_union(&ps->all_damage, &ps->all_damage, (region_t *)damage);
pixman_region32_union(ps->damage, ps->damage, (region_t *)damage);
}

// === Fading ===
Expand Down Expand Up @@ -1082,7 +1050,10 @@ configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {

rebuild_screen_reg(ps);
rebuild_shadow_exclude_reg(ps);
free_all_damage_last(ps);
for (int i = 0; i < ps->ndamage; i++) {
pixman_region32_clear(&ps->damage_ring[i]);
}
ps->damage = ps->damage_ring + ps->ndamage - 1;

// Re-redirect screen if required
if (ps->o.reredir_on_root_change && ps->redirected) {
Expand Down Expand Up @@ -1281,7 +1252,6 @@ ev_xcb_error(session_t attr_unused *ps, xcb_generic_error_t *err) {

static void
expose_root(session_t *ps, const rect_t *rects, int nrects) {
free_all_damage_last(ps);
region_t region;
pixman_region32_init_rects(&region, rects, nrects);
add_damage(ps, &region);
Expand Down Expand Up @@ -2424,25 +2394,9 @@ _draw_callback(EV_P_ session_t *ps, int revents) {
}

// If the screen is unredirected, free all_damage to stop painting
if (!ps->redirected || ps->o.stoppaint_force == ON)
pixman_region32_clear(&ps->all_damage);

if (pixman_region32_not_empty(&ps->all_damage)) {
region_t all_damage_orig, *region_real = NULL;
pixman_region32_init(&all_damage_orig);

// keep a copy of non-resized all_damage for region_real
if (ps->o.resize_damage > 0) {
copy_region(&all_damage_orig, &ps->all_damage);
resize_region(ps, &ps->all_damage, ps->o.resize_damage);
region_real = &all_damage_orig;
}

if (ps->redirected && ps->o.stoppaint_force != ON) {
static int paint = 0;
paint_all(ps, &ps->all_damage, region_real, t);

pixman_region32_clear(&ps->all_damage);
pixman_region32_fini(&all_damage_orig);
paint_all(ps, t, false);

paint++;
if (ps->o.benchmark && paint >= ps->o.benchmark)
Expand Down Expand Up @@ -2710,9 +2664,6 @@ session_init(session_t *ps_old, int argc, char **argv) {
*ps = s_def;
ps->loop = EV_DEFAULT;
pixman_region32_init(&ps->screen_reg);
pixman_region32_init(&ps->all_damage);
for (int i = 0; i < CGLX_MAX_BUFFER_AGE; i ++)
pixman_region32_init(&ps->all_damage_last[i]);

ps_g = ps;
ps->ignore_tail = &ps->ignore_head;
Expand Down Expand Up @@ -3193,9 +3144,10 @@ session_destroy(session_t *ps) {
free_paint(ps, &ps->tgt_buffer);

pixman_region32_fini(&ps->screen_reg);
pixman_region32_fini(&ps->all_damage);
for (int i = 0; i < CGLX_MAX_BUFFER_AGE; ++i)
pixman_region32_fini(&ps->all_damage_last[i]);
for (int i = 0; i < ps->ndamage; ++i)
pixman_region32_fini(&ps->damage_ring[i]);
ps->ndamage = 0;
ps->damage_ring = ps->damage = NULL;
free(ps->expose_rects);

free(ps->o.config_file);
Expand Down Expand Up @@ -3304,7 +3256,7 @@ session_run(session_t *ps) {
t = paint_preprocess(ps, ps->list);

if (ps->redirected)
paint_all(ps, NULL, NULL, t);
paint_all(ps, t, true);

// In benchmark mode, we want draw_idle handler to always be active
if (ps->o.benchmark)
Expand Down
60 changes: 0 additions & 60 deletions src/opengl.c
Original file line number Diff line number Diff line change
Expand Up @@ -857,66 +857,6 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
glx_check_err(ps);
}

/**
* Preprocess function before start painting.
*/
void
glx_paint_pre(session_t *ps, region_t *preg) {
ps->psglx->z = 0.0;
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Get buffer age
bool trace_damage = (ps->o.glx_swap_method < 0 || ps->o.glx_swap_method > 1);

// Trace raw damage regions
region_t newdamage;
pixman_region32_init(&newdamage);
if (trace_damage)
copy_region(&newdamage, preg);

// We use GLX buffer_age extension to decide which pixels in
// the back buffer is reusable, and limit our redrawing
int buffer_age = 0;

// Query GLX_EXT_buffer_age for buffer age
if (ps->o.glx_swap_method == SWAPM_BUFFER_AGE) {
unsigned val = 0;
glXQueryDrawable(ps->dpy, get_tgt_window(ps),
GLX_BACK_BUFFER_AGE_EXT, &val);
buffer_age = val;
}

// Buffer age too high
if (buffer_age > CGLX_MAX_BUFFER_AGE + 1)
buffer_age = 0;

assert(buffer_age >= 0);

if (buffer_age) {
// Determine paint area
for (int i = 0; i < buffer_age - 1; ++i)
pixman_region32_union(preg, preg, &ps->all_damage_last[i]);
} else
// buffer_age == 0 means buffer age is not available, paint everything
copy_region(preg, &ps->screen_reg);

if (trace_damage) {
// XXX use a circular queue instead of memmove
pixman_region32_fini(&ps->all_damage_last[CGLX_MAX_BUFFER_AGE - 1]);
memmove(ps->all_damage_last + 1, ps->all_damage_last,
(CGLX_MAX_BUFFER_AGE - 1) * sizeof(region_t));
ps->all_damage_last[0] = newdamage;
}

glx_set_clip(ps, preg);

#ifdef DEBUG_GLX_PAINTREG
glx_render_color(ps, 0, 0, ps->root_width, ps->root_height, 0, *preg, NULL);
#endif

glx_check_err(ps);
}

/**
* Set clipping region on the target window.
*/
Expand Down
Loading

0 comments on commit e80ff85

Please sign in to comment.