backend interface: Add visible hint
Pass the visible region of the image to the backend, so the backend could optimize based on that information. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
@ -6,9 +6,9 @@
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "region.h"
|
||||
#include "win.h"
|
||||
#include "log.h"
|
||||
|
||||
backend_init_fn backend_list[NUM_BKEND] = {
|
||||
[BKEND_XRENDER] = backend_xrender_init,
|
||||
@ -37,16 +37,19 @@ region_t get_damage(session_t *ps) {
|
||||
|
||||
/// paint all windows
|
||||
void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
||||
region_t region;
|
||||
// All painting will be limited to the damage, if _some_ of
|
||||
// the paints bleed out of the damage region, it will destroy
|
||||
// part of the image we want to reuse
|
||||
region_t reg_damage;
|
||||
if (!ignore_damage) {
|
||||
region = get_damage(ps);
|
||||
reg_damage = get_damage(ps);
|
||||
} else {
|
||||
pixman_region32_init(®ion);
|
||||
pixman_region32_copy(®ion, &ps->screen_reg);
|
||||
pixman_region32_init(®_damage);
|
||||
pixman_region32_copy(®_damage, &ps->screen_reg);
|
||||
}
|
||||
|
||||
if (!pixman_region32_not_empty(®ion)) {
|
||||
pixman_region32_fini(®ion);
|
||||
if (!pixman_region32_not_empty(®_damage)) {
|
||||
pixman_region32_fini(®_damage);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -54,27 +57,26 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
||||
static struct timespec last_paint = {0};
|
||||
#endif
|
||||
|
||||
region_t reg_tmp;
|
||||
const region_t *reg_paint;
|
||||
pixman_region32_init(®_tmp);
|
||||
// A hint to backend, the region that will be visible on screen
|
||||
// backend can optimize based on this info
|
||||
region_t reg_visible;
|
||||
pixman_region32_init(®_visible);
|
||||
pixman_region32_copy(®_visible, &ps->screen_reg);
|
||||
if (t) {
|
||||
// Calculate the region upon which the root window (wallpaper) is to be
|
||||
// painted based on the ignore region of the lowest window, if available
|
||||
pixman_region32_subtract(®_tmp, ®ion, t->reg_ignore);
|
||||
reg_paint = ®_tmp;
|
||||
} else {
|
||||
reg_paint = ®ion;
|
||||
pixman_region32_subtract(®_visible, ®_visible, t->reg_ignore);
|
||||
}
|
||||
|
||||
// TODO Bind root pixmap
|
||||
|
||||
if (ps->backend_data->ops->prepare) {
|
||||
ps->backend_data->ops->prepare(ps->backend_data, reg_paint);
|
||||
ps->backend_data->ops->prepare(ps->backend_data, ®_visible);
|
||||
}
|
||||
|
||||
if (ps->root_image) {
|
||||
ps->backend_data->ops->compose(ps->backend_data, ps->root_image, 0, 0,
|
||||
reg_paint);
|
||||
®_damage, ®_visible);
|
||||
}
|
||||
|
||||
// Windows are sorted from bottom to top
|
||||
@ -83,28 +85,25 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
||||
//
|
||||
// Whether this is beneficial is to be determined XXX
|
||||
for (win *w = t; w; w = w->prev_trans) {
|
||||
// Calculate the region based on the reg_ignore of the next (higher)
|
||||
// window and the bounding region
|
||||
// XXX XXX
|
||||
pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore);
|
||||
|
||||
if (!pixman_region32_not_empty(®_tmp)) {
|
||||
continue;
|
||||
}
|
||||
pixman_region32_subtract(®_visible, &ps->screen_reg, w->reg_ignore);
|
||||
|
||||
// The bounding shape of the window, in global/target coordinates
|
||||
// reminder: bounding shape contains the WM frame
|
||||
auto reg_bound = win_get_bounding_shape_global_by_val(w);
|
||||
|
||||
// Draw shadow on target
|
||||
if (w->shadow) {
|
||||
// Clip region for the shadow
|
||||
// reg_shadow \in reg_damage
|
||||
auto reg_shadow = win_extents_by_val(w);
|
||||
pixman_region32_intersect(®_shadow, ®_shadow, ®_tmp);
|
||||
|
||||
pixman_region32_intersect(®_shadow, ®_shadow, ®_damage);
|
||||
if (!ps->o.wintype_option[w->window_type].full_shadow) {
|
||||
pixman_region32_subtract(®_shadow, ®_shadow, ®_bound);
|
||||
}
|
||||
|
||||
// Mask out the region we don't want shadow on
|
||||
if (pixman_region32_not_empty(&ps->shadow_exclude_reg)) {
|
||||
pixman_region32_subtract(®_tmp, ®_tmp,
|
||||
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||
&ps->shadow_exclude_reg);
|
||||
}
|
||||
|
||||
@ -123,17 +122,18 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
||||
}
|
||||
|
||||
assert(w->shadow_image);
|
||||
ps->backend_data->ops->compose(ps->backend_data, w->shadow_image,
|
||||
w->g.x + w->shadow_dx,
|
||||
w->g.y + w->shadow_dy, ®_shadow);
|
||||
ps->backend_data->ops->compose(
|
||||
ps->backend_data, w->shadow_image, w->g.x + w->shadow_dx,
|
||||
w->g.y + w->shadow_dy, ®_shadow, ®_visible);
|
||||
pixman_region32_fini(®_shadow);
|
||||
}
|
||||
|
||||
pixman_region32_intersect(®_tmp, ®_tmp, ®_bound);
|
||||
pixman_region32_fini(®_bound);
|
||||
if (!pixman_region32_not_empty(®_tmp)) {
|
||||
continue;
|
||||
}
|
||||
// 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);
|
||||
|
||||
// Blur window background
|
||||
bool win_transparent = ps->backend_data->ops->is_image_transparent(
|
||||
ps->backend_data, w->win_image);
|
||||
@ -142,35 +142,61 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
||||
(win_transparent || (ps->o.blur_background_frame && frame_transparent))) {
|
||||
// Minimize the region we try to blur, if the window
|
||||
// itself is not opaque, only the frame is.
|
||||
if (win_is_solid(ps, w)) {
|
||||
region_t reg_blur;
|
||||
pixman_region32_init(®_blur);
|
||||
win_get_region_noframe_local(w, ®_blur);
|
||||
// TODO resize blur region to fix black line artifact
|
||||
if (!win_is_solid(ps, w)) {
|
||||
// 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,
|
||||
®_paint, ®_visible);
|
||||
} else if (frame_transparent && ps->o.blur_background_frame) {
|
||||
// Window itself is solid, we only need to blur the frame region
|
||||
auto reg_blur = win_get_region_frame_local_by_val(w);
|
||||
pixman_region32_translate(®_blur, w->g.x, w->g.y);
|
||||
pixman_region32_subtract(®_blur, ®_tmp, ®_blur);
|
||||
// make sure reg_blur \in reg_damage
|
||||
pixman_region32_intersect(®_blur, ®_blur, ®_damage);
|
||||
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
|
||||
®_blur);
|
||||
®_blur, ®_visible);
|
||||
pixman_region32_fini(®_blur);
|
||||
} else {
|
||||
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
|
||||
®_tmp);
|
||||
}
|
||||
}
|
||||
// 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, ®_tmp);
|
||||
ps->backend_data->ops->compose(ps->backend_data, w->win_image, w->g.x,
|
||||
w->g.y, ®_paint, ®_visible);
|
||||
} else {
|
||||
region_t reg_local;
|
||||
pixman_region32_init(®_local);
|
||||
pixman_region32_copy(®_local, ®_tmp);
|
||||
pixman_region32_translate(®_local, -w->g.x, -w->g.y);
|
||||
// For window image processing, we don't need to limit the process
|
||||
// region to damage, since the window image data is independent from
|
||||
// the target image data, which we want to protect.
|
||||
|
||||
// The bounding shape, in window local coordinates
|
||||
region_t reg_bound_local;
|
||||
pixman_region32_init(®_bound_local);
|
||||
pixman_region32_copy(®_bound_local, ®_bound);
|
||||
pixman_region32_translate(®_bound_local, -w->g.x, -w->g.y);
|
||||
|
||||
// The visible region, in window local coordinates
|
||||
// Although we don't limit process region to damage, we provide
|
||||
// that info in reg_visible as a hint. Since window image data
|
||||
// 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_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 shape
|
||||
// yet. So pass that as the visible region, not the clip region.
|
||||
pixman_region32_intersect(®_visible_local, ®_visible_local,
|
||||
®_bound_local);
|
||||
|
||||
// A region covers the entire window
|
||||
region_t reg_win;
|
||||
pixman_region32_init_rect(®_win, 0, 0, w->g.width, w->g.height);
|
||||
auto new_img = ps->backend_data->ops->copy(
|
||||
ps->backend_data, w->win_image, ®_local);
|
||||
ps->backend_data, w->win_image, ®_visible_local);
|
||||
if (w->invert_color) {
|
||||
ps->backend_data->ops->image_op(ps->backend_data,
|
||||
IMAGE_OP_INVERT_COLOR,
|
||||
new_img, ®_local, NULL);
|
||||
ps->backend_data->ops->image_op(
|
||||
ps->backend_data, IMAGE_OP_INVERT_COLOR, new_img,
|
||||
®_win, ®_visible_local, NULL);
|
||||
}
|
||||
if (w->dim) {
|
||||
double dim_opacity = ps->o.inactive_dim;
|
||||
@ -178,30 +204,32 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
||||
dim_opacity *= w->opacity;
|
||||
}
|
||||
ps->backend_data->ops->image_op(
|
||||
ps->backend_data, IMAGE_OP_DIM, new_img, ®_local,
|
||||
(double[]){dim_opacity});
|
||||
ps->backend_data, IMAGE_OP_DIM, new_img, ®_win,
|
||||
®_visible_local, (double[]){dim_opacity});
|
||||
}
|
||||
if (w->frame_opacity != 1) {
|
||||
auto reg_frame = win_get_region_noframe_local_by_val(w);
|
||||
pixman_region32_subtract(®_frame, ®_local, ®_frame);
|
||||
auto reg_frame = win_get_region_frame_local_by_val(w);
|
||||
ps->backend_data->ops->image_op(
|
||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img,
|
||||
®_frame, (double[]){w->frame_opacity});
|
||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, ®_frame,
|
||||
®_visible_local, (double[]){w->frame_opacity});
|
||||
pixman_region32_fini(®_frame);
|
||||
}
|
||||
if (w->opacity != 1) {
|
||||
ps->backend_data->ops->image_op(
|
||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, NULL,
|
||||
(double[]){w->opacity});
|
||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA_ALL, new_img,
|
||||
NULL, ®_visible_local, (double[]){w->opacity});
|
||||
}
|
||||
ps->backend_data->ops->compose(ps->backend_data, new_img, w->g.x,
|
||||
w->g.y, ®_tmp);
|
||||
w->g.y, ®_paint, ®_visible);
|
||||
ps->backend_data->ops->release_image(ps->backend_data, new_img);
|
||||
pixman_region32_fini(®_win);
|
||||
pixman_region32_fini(®_visible_local);
|
||||
pixman_region32_fini(®_bound_local);
|
||||
}
|
||||
pixman_region32_fini(®_bound);
|
||||
pixman_region32_fini(®_paint);
|
||||
}
|
||||
|
||||
// Free up all temporary regions
|
||||
pixman_region32_fini(®_tmp);
|
||||
|
||||
if (ps->backend_data->ops->present) {
|
||||
// Present the rendered scene
|
||||
// Vsync is done here
|
||||
|
Reference in New Issue
Block a user