From 06dba4b196dd6c43e97f38f8ee10cefb85e0639e Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 26 Jul 2019 00:00:51 +0100 Subject: [PATCH] backend: do partial updates Although the functionality is not implemented by any backends yet. Signed-off-by: Yuxuan Shui --- src/backend/backend.c | 81 +++++++++++++++++++++++++++++-------------- src/compton.c | 5 +++ src/win.h | 2 ++ 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/backend/backend.c b/src/backend/backend.c index 9a9f7c6..054f192 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -71,6 +71,32 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { static struct timespec last_paint = {0}; #endif + region_t reg_paint; + assert(ps->o.blur_method != BLUR_METHOD_INVALID); + if (ps->o.blur_method != BLUR_METHOD_NONE && ps->backend_data->ops->get_blur_size) { + int blur_width, blur_height; + ps->backend_data->ops->get_blur_size(ps->backend_blur_context, + &blur_width, &blur_height); + if (t) { + // The region of screen a given window influences will be smeared + // out by blur. With more windows on top of the given window, the + // influences region will be smeared out more. + // + // Instead of accurately calculate how much bigger the damage + // region will be because of blur, we assume the worst case here. + // That is, the damaged window is at the bottom of the stack, and + // all other windows have semi-transparent background + resize_region_in_place(®_damage, blur_width * t->stacking_rank, + blur_height * t->stacking_rank); + pixman_region32_intersect(®_damage, ®_damage, &ps->screen_reg); + } + reg_paint = resize_region(®_damage, blur_width, blur_height); + pixman_region32_intersect(®_paint, ®_paint, &ps->screen_reg); + } else { + pixman_region32_init(®_paint); + pixman_region32_copy(®_paint, ®_damage); + } + // A hint to backend, the region that will be visible on screen // backend can optimize based on this info region_t reg_visible; @@ -85,12 +111,12 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { // TODO Bind root pixmap if (ps->backend_data->ops->prepare) { - ps->backend_data->ops->prepare(ps->backend_data, ®_damage); + ps->backend_data->ops->prepare(ps->backend_data, ®_paint); } if (ps->root_image) { ps->backend_data->ops->compose(ps->backend_data, ps->root_image, 0, 0, - ®_damage, ®_visible); + ®_paint, ®_visible); } // Windows are sorted from bottom to top @@ -109,9 +135,9 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { // Draw shadow on target if (w->shadow) { // Clip region for the shadow - // reg_shadow \in reg_damage + // reg_shadow \in reg_paint auto reg_shadow = win_extents_by_val(w); - pixman_region32_intersect(®_shadow, ®_shadow, ®_damage); + pixman_region32_intersect(®_shadow, ®_shadow, ®_paint); if (!ps->o.wintype_option[w->window_type].full_shadow) { pixman_region32_subtract(®_shadow, ®_shadow, ®_bound); } @@ -156,10 +182,10 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { } // The clip region for the current window, in global/target coordinates - // reg_paint \in reg_damage - region_t reg_paint; - pixman_region32_init(®_paint); - pixman_region32_intersect(®_paint, ®_bound, ®_damage); + // reg_paint_in_bound \in reg_paint + region_t reg_paint_in_bound; + pixman_region32_init(®_paint_in_bound); + pixman_region32_intersect(®_paint_in_bound, ®_bound, ®_paint); // Blur window background // TODO since the background might change the content of the window (e.g. @@ -176,10 +202,10 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { // TODO resize blur region to fix black line artifact if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) { // We need to blur the bounding shape of the window - // (reg_paint = reg_bound \cap reg_damage) - ps->backend_data->ops->blur(ps->backend_data, w->opacity, - ps->backend_blur_context, - ®_paint, ®_visible); + // (reg_paint_in_bound = reg_bound \cap reg_paint) + ps->backend_data->ops->blur( + ps->backend_data, w->opacity, ps->backend_blur_context, + ®_paint_in_bound, ®_visible); } else { // Window itself is solid, we only need to blur the frame // region @@ -190,8 +216,8 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { auto reg_blur = win_get_region_frame_local_by_val(w); pixman_region32_translate(®_blur, w->g.x, w->g.y); - // make sure reg_blur \in reg_damage - pixman_region32_intersect(®_blur, ®_blur, ®_damage); + // make sure reg_blur \in reg_paint + pixman_region32_intersect(®_blur, ®_blur, ®_paint); ps->backend_data->ops->blur(ps->backend_data, w->opacity, ps->backend_blur_context, ®_blur, ®_visible); @@ -200,8 +226,9 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { } // Draw window on target if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) { - ps->backend_data->ops->compose(ps->backend_data, w->win_image, w->g.x, - w->g.y, ®_paint, ®_visible); + ps->backend_data->ops->compose(ps->backend_data, w->win_image, + w->g.x, w->g.y, + ®_paint_in_bound, ®_visible); } else { // For window image processing, we don't need to limit the process // region to damage, since the window image data is independent @@ -219,7 +246,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { // outside of the damage region won't be painted onto target region_t reg_visible_local; pixman_region32_init(®_visible_local); - pixman_region32_intersect(®_visible_local, ®_visible, ®_damage); + pixman_region32_intersect(®_visible_local, ®_visible, ®_paint); pixman_region32_translate(®_visible_local, -w->g.x, -w->g.y); // Data outside of the bounding shape won't be visible, but it is // not necessary to limit the image operations to the bounding @@ -228,7 +255,6 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { pixman_region32_intersect(®_visible_local, ®_visible_local, ®_bound_local); - // A region covers the entire window auto new_img = ps->backend_data->ops->copy( ps->backend_data, w->win_image, ®_visible_local); if (w->invert_color) { @@ -258,21 +284,22 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { NULL, ®_visible_local, (double[]){w->opacity}); } ps->backend_data->ops->compose(ps->backend_data, new_img, w->g.x, - w->g.y, ®_paint, ®_visible); + w->g.y, ®_paint_in_bound, + ®_visible); ps->backend_data->ops->release_image(ps->backend_data, new_img); pixman_region32_fini(®_visible_local); pixman_region32_fini(®_bound_local); } pixman_region32_fini(®_bound); - pixman_region32_fini(®_paint); + pixman_region32_fini(®_paint_in_bound); } - pixman_region32_fini(®_damage); + pixman_region32_fini(®_paint); if (ps->o.monitor_repaint) { - reg_damage = get_damage(ps, false); - ps->backend_data->ops->fill(ps->backend_data, - (struct color){0.5, 0, 0, 0.5}, ®_damage); - pixman_region32_fini(®_damage); + auto reg_damage_debug = get_damage(ps, false); + ps->backend_data->ops->fill( + ps->backend_data, (struct color){0.5, 0, 0, 0.5}, ®_damage_debug); + pixman_region32_fini(®_damage_debug); } // Move the head of the damage ring @@ -285,9 +312,11 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { if (ps->backend_data->ops->present) { // Present the rendered scene // Vsync is done here - ps->backend_data->ops->present(ps->backend_data, NULL); + ps->backend_data->ops->present(ps->backend_data, ®_damage); } + pixman_region32_fini(®_damage); + #ifdef DEBUG_REPAINT struct timespec now = get_time_timespec(); struct timespec diff = {0}; diff --git a/src/compton.c b/src/compton.c index 3975e0c..447068c 100644 --- a/src/compton.c +++ b/src/compton.c @@ -575,6 +575,11 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) { } w->prev_trans = bottom; + if (bottom) { + w->stacking_rank = bottom->stacking_rank + 1; + } else { + w->stacking_rank = 0; + } bottom = w; // If the screen is not redirected and the window has redir_ignore set, diff --git a/src/win.h b/src/win.h index d1559f3..90e6af4 100644 --- a/src/win.h +++ b/src/win.h @@ -169,6 +169,8 @@ struct managed_win { void *shadow_image; /// Pointer to the next higher window to paint. struct managed_win *prev_trans; + /// Number of windows above this window + int stacking_rank; // TODO rethink reg_ignore // Core members