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:
parent
a2ae36c1d6
commit
c57f267535
|
@ -6,9 +6,9 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
backend_init_fn backend_list[NUM_BKEND] = {
|
backend_init_fn backend_list[NUM_BKEND] = {
|
||||||
[BKEND_XRENDER] = backend_xrender_init,
|
[BKEND_XRENDER] = backend_xrender_init,
|
||||||
|
@ -37,16 +37,19 @@ region_t get_damage(session_t *ps) {
|
||||||
|
|
||||||
/// paint all windows
|
/// paint all windows
|
||||||
void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
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) {
|
if (!ignore_damage) {
|
||||||
region = get_damage(ps);
|
reg_damage = get_damage(ps);
|
||||||
} else {
|
} else {
|
||||||
pixman_region32_init(®ion);
|
pixman_region32_init(®_damage);
|
||||||
pixman_region32_copy(®ion, &ps->screen_reg);
|
pixman_region32_copy(®_damage, &ps->screen_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pixman_region32_not_empty(®ion)) {
|
if (!pixman_region32_not_empty(®_damage)) {
|
||||||
pixman_region32_fini(®ion);
|
pixman_region32_fini(®_damage);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,27 +57,26 @@ void paint_all_new(session_t *ps, win *const t, bool ignore_damage) {
|
||||||
static struct timespec last_paint = {0};
|
static struct timespec last_paint = {0};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
region_t reg_tmp;
|
// A hint to backend, the region that will be visible on screen
|
||||||
const region_t *reg_paint;
|
// backend can optimize based on this info
|
||||||
pixman_region32_init(®_tmp);
|
region_t reg_visible;
|
||||||
|
pixman_region32_init(®_visible);
|
||||||
|
pixman_region32_copy(®_visible, &ps->screen_reg);
|
||||||
if (t) {
|
if (t) {
|
||||||
// Calculate the region upon which the root window (wallpaper) is to be
|
// Calculate the region upon which the root window (wallpaper) is to be
|
||||||
// painted based on the ignore region of the lowest window, if available
|
// painted based on the ignore region of the lowest window, if available
|
||||||
pixman_region32_subtract(®_tmp, ®ion, t->reg_ignore);
|
pixman_region32_subtract(®_visible, ®_visible, t->reg_ignore);
|
||||||
reg_paint = ®_tmp;
|
|
||||||
} else {
|
|
||||||
reg_paint = ®ion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Bind root pixmap
|
// TODO Bind root pixmap
|
||||||
|
|
||||||
if (ps->backend_data->ops->prepare) {
|
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) {
|
if (ps->root_image) {
|
||||||
ps->backend_data->ops->compose(ps->backend_data, ps->root_image, 0, 0,
|
ps->backend_data->ops->compose(ps->backend_data, ps->root_image, 0, 0,
|
||||||
reg_paint);
|
®_damage, ®_visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Windows are sorted from bottom to top
|
// 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
|
// Whether this is beneficial is to be determined XXX
|
||||||
for (win *w = t; w; w = w->prev_trans) {
|
for (win *w = t; w; w = w->prev_trans) {
|
||||||
// Calculate the region based on the reg_ignore of the next (higher)
|
pixman_region32_subtract(®_visible, &ps->screen_reg, w->reg_ignore);
|
||||||
// window and the bounding region
|
|
||||||
// XXX XXX
|
|
||||||
pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore);
|
|
||||||
|
|
||||||
if (!pixman_region32_not_empty(®_tmp)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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);
|
auto reg_bound = win_get_bounding_shape_global_by_val(w);
|
||||||
|
|
||||||
// Draw shadow on target
|
// Draw shadow on target
|
||||||
if (w->shadow) {
|
if (w->shadow) {
|
||||||
|
// Clip region for the shadow
|
||||||
|
// reg_shadow \in reg_damage
|
||||||
auto reg_shadow = win_extents_by_val(w);
|
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) {
|
if (!ps->o.wintype_option[w->window_type].full_shadow) {
|
||||||
pixman_region32_subtract(®_shadow, ®_shadow, ®_bound);
|
pixman_region32_subtract(®_shadow, ®_shadow, ®_bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mask out the region we don't want shadow on
|
// Mask out the region we don't want shadow on
|
||||||
if (pixman_region32_not_empty(&ps->shadow_exclude_reg)) {
|
if (pixman_region32_not_empty(&ps->shadow_exclude_reg)) {
|
||||||
pixman_region32_subtract(®_tmp, ®_tmp,
|
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||||
&ps->shadow_exclude_reg);
|
&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);
|
assert(w->shadow_image);
|
||||||
ps->backend_data->ops->compose(ps->backend_data, w->shadow_image,
|
ps->backend_data->ops->compose(
|
||||||
w->g.x + w->shadow_dx,
|
ps->backend_data, w->shadow_image, w->g.x + w->shadow_dx,
|
||||||
w->g.y + w->shadow_dy, ®_shadow);
|
w->g.y + w->shadow_dy, ®_shadow, ®_visible);
|
||||||
pixman_region32_fini(®_shadow);
|
pixman_region32_fini(®_shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_intersect(®_tmp, ®_tmp, ®_bound);
|
// The clip region for the current window, in global/target coordinates
|
||||||
pixman_region32_fini(®_bound);
|
// reg_paint \in reg_damage
|
||||||
if (!pixman_region32_not_empty(®_tmp)) {
|
region_t reg_paint;
|
||||||
continue;
|
pixman_region32_init(®_paint);
|
||||||
}
|
pixman_region32_intersect(®_paint, ®_bound, ®_damage);
|
||||||
|
|
||||||
// Blur window background
|
// Blur window background
|
||||||
bool win_transparent = ps->backend_data->ops->is_image_transparent(
|
bool win_transparent = ps->backend_data->ops->is_image_transparent(
|
||||||
ps->backend_data, w->win_image);
|
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))) {
|
(win_transparent || (ps->o.blur_background_frame && frame_transparent))) {
|
||||||
// Minimize the region we try to blur, if the window
|
// Minimize the region we try to blur, if the window
|
||||||
// itself is not opaque, only the frame is.
|
// itself is not opaque, only the frame is.
|
||||||
if (win_is_solid(ps, w)) {
|
// TODO resize blur region to fix black line artifact
|
||||||
region_t reg_blur;
|
if (!win_is_solid(ps, w)) {
|
||||||
pixman_region32_init(®_blur);
|
// We need to blur the bounding shape of the window
|
||||||
win_get_region_noframe_local(w, ®_blur);
|
// (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_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,
|
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
|
||||||
®_blur);
|
®_blur, ®_visible);
|
||||||
pixman_region32_fini(®_blur);
|
pixman_region32_fini(®_blur);
|
||||||
} else {
|
|
||||||
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
|
|
||||||
®_tmp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Draw window on target
|
// Draw window on target
|
||||||
if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) {
|
if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) {
|
||||||
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
|
ps->backend_data->ops->compose(ps->backend_data, w->win_image, w->g.x,
|
||||||
w->g.x, w->g.y, ®_tmp);
|
w->g.y, ®_paint, ®_visible);
|
||||||
} else {
|
} else {
|
||||||
region_t reg_local;
|
// For window image processing, we don't need to limit the process
|
||||||
pixman_region32_init(®_local);
|
// region to damage, since the window image data is independent from
|
||||||
pixman_region32_copy(®_local, ®_tmp);
|
// the target image data, which we want to protect.
|
||||||
pixman_region32_translate(®_local, -w->g.x, -w->g.y);
|
|
||||||
|
// 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(
|
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) {
|
if (w->invert_color) {
|
||||||
ps->backend_data->ops->image_op(ps->backend_data,
|
ps->backend_data->ops->image_op(
|
||||||
IMAGE_OP_INVERT_COLOR,
|
ps->backend_data, IMAGE_OP_INVERT_COLOR, new_img,
|
||||||
new_img, ®_local, NULL);
|
®_win, ®_visible_local, NULL);
|
||||||
}
|
}
|
||||||
if (w->dim) {
|
if (w->dim) {
|
||||||
double dim_opacity = ps->o.inactive_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;
|
dim_opacity *= w->opacity;
|
||||||
}
|
}
|
||||||
ps->backend_data->ops->image_op(
|
ps->backend_data->ops->image_op(
|
||||||
ps->backend_data, IMAGE_OP_DIM, new_img, ®_local,
|
ps->backend_data, IMAGE_OP_DIM, new_img, ®_win,
|
||||||
(double[]){dim_opacity});
|
®_visible_local, (double[]){dim_opacity});
|
||||||
}
|
}
|
||||||
if (w->frame_opacity != 1) {
|
if (w->frame_opacity != 1) {
|
||||||
auto reg_frame = win_get_region_noframe_local_by_val(w);
|
auto reg_frame = win_get_region_frame_local_by_val(w);
|
||||||
pixman_region32_subtract(®_frame, ®_local, ®_frame);
|
|
||||||
ps->backend_data->ops->image_op(
|
ps->backend_data->ops->image_op(
|
||||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img,
|
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, ®_frame,
|
||||||
®_frame, (double[]){w->frame_opacity});
|
®_visible_local, (double[]){w->frame_opacity});
|
||||||
|
pixman_region32_fini(®_frame);
|
||||||
}
|
}
|
||||||
if (w->opacity != 1) {
|
if (w->opacity != 1) {
|
||||||
ps->backend_data->ops->image_op(
|
ps->backend_data->ops->image_op(
|
||||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, NULL,
|
ps->backend_data, IMAGE_OP_APPLY_ALPHA_ALL, new_img,
|
||||||
(double[]){w->opacity});
|
NULL, ®_visible_local, (double[]){w->opacity});
|
||||||
}
|
}
|
||||||
ps->backend_data->ops->compose(ps->backend_data, new_img, w->g.x,
|
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);
|
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) {
|
if (ps->backend_data->ops->present) {
|
||||||
// Present the rendered scene
|
// Present the rendered scene
|
||||||
// Vsync is done here
|
// Vsync is done here
|
||||||
|
|
|
@ -23,9 +23,15 @@ typedef struct backend_base {
|
||||||
} backend_t;
|
} backend_t;
|
||||||
|
|
||||||
enum image_operations {
|
enum image_operations {
|
||||||
|
// Invert the color of the image
|
||||||
IMAGE_OP_INVERT_COLOR,
|
IMAGE_OP_INVERT_COLOR,
|
||||||
|
// Dim the image, argument is the percentage
|
||||||
IMAGE_OP_DIM,
|
IMAGE_OP_DIM,
|
||||||
|
// Multiply the alpha channel by the argument
|
||||||
IMAGE_OP_APPLY_ALPHA,
|
IMAGE_OP_APPLY_ALPHA,
|
||||||
|
// Same as APPLY_ALPHA, but `reg_op` is ignored and the operation applies to the
|
||||||
|
// full image
|
||||||
|
IMAGE_OP_APPLY_ALPHA_ALL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct backend_operations {
|
struct backend_operations {
|
||||||
|
@ -64,25 +70,29 @@ struct backend_operations {
|
||||||
/// Optional?
|
/// Optional?
|
||||||
void (*prepare)(backend_t *backend_data, const region_t *reg_paint);
|
void (*prepare)(backend_t *backend_data, const region_t *reg_paint);
|
||||||
|
|
||||||
/// Paint the content of an imageonto the (possibly buffered)
|
/**
|
||||||
/// target picture. Always called after render_win(). Maybe called
|
* Paint the content of an image onto the (possibly buffered)
|
||||||
/// multiple times between render_win() and finish_render_win().
|
* target picture.
|
||||||
/// The origin is the top left of the window, exclude the shadow,
|
*
|
||||||
/// (dst_x, dst_y) refers to where the origin should be in the target
|
* @param backend_data the backend data
|
||||||
/// buffer.
|
* @param image_data the image to paint
|
||||||
|
* @param dst_x, dst_y the top left corner of the image in the target
|
||||||
|
* @param reg_paint the clip region, in target coordinates
|
||||||
|
* @param reg_visibile the visible region, in target coordinates
|
||||||
|
*/
|
||||||
void (*compose)(backend_t *backend_data, void *image_data, int dst_x, int dst_y,
|
void (*compose)(backend_t *backend_data, void *image_data, int dst_x, int dst_y,
|
||||||
const region_t *reg_paint);
|
const region_t *reg_paint, const region_t *reg_visible);
|
||||||
|
|
||||||
/// Blur a given region on of the target.
|
/// Blur a given region on of the target.
|
||||||
bool (*blur)(backend_t *backend_data, double opacity, const region_t *)
|
bool (*blur)(backend_t *backend_data, double opacity, const region_t *reg_blur,
|
||||||
__attribute__((nonnull(1, 3)));
|
const region_t *reg_visible) attr_nonnull(1, 3, 4);
|
||||||
|
|
||||||
/// Present the buffered target picture onto the screen. If target
|
/// Present the buffered target picture onto the screen. If target
|
||||||
/// is not buffered, this should be NULL. Otherwise, it should always
|
/// is not buffered, this should be NULL. Otherwise, it should always
|
||||||
/// be non-NULL.
|
/// be non-NULL.
|
||||||
///
|
///
|
||||||
/// Optional
|
/// Optional
|
||||||
void (*present)(backend_t *backend_data) __attribute__((nonnull(1)));
|
void (*present)(backend_t *backend_data) attr_nonnull(1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a X pixmap to the backend's internal image data structure.
|
* Bind a X pixmap to the backend's internal image data structure.
|
||||||
|
@ -137,17 +147,22 @@ struct backend_operations {
|
||||||
* Manipulate an image
|
* Manipulate an image
|
||||||
*
|
*
|
||||||
* @param backend_data backend data
|
* @param backend_data backend data
|
||||||
* @param op the operation to perform
|
* @param op the operation to perform
|
||||||
* @param image_data an image data structure returned by the backend
|
* @param image_data an image data structure returned by the backend
|
||||||
* @param reg_paint the clip region, limit the region of the image to be
|
* @param reg_op the clip region, define the part of the image to be
|
||||||
* manipulated
|
* operated on.
|
||||||
* @param args extra arguments, specific to each operation
|
* @param reg_visible define the part of the image that will eventually
|
||||||
* @return a new image data structure contains the same image as `image_data`
|
* be visible on screen. this is a hint to the backend
|
||||||
|
* for optimization purposes.
|
||||||
|
* @param args extra arguments, operation specific
|
||||||
|
* @return a new image data structure containing the result
|
||||||
*/
|
*/
|
||||||
void (*image_op)(backend_t *backend_data, enum image_operations op,
|
bool (*image_op)(backend_t *backend_data, enum image_operations op, void *image_data,
|
||||||
void *image_data, const region_t *reg_paint, void *args);
|
const region_t *reg_op, const region_t *reg_visible, void *args);
|
||||||
|
|
||||||
void *(*copy)(backend_t *base, const void *image_data, const region_t *reg_copy);
|
/// Create another instance of the `image_data`. All `image_op` calls on the
|
||||||
|
/// returned image should not affect the original image
|
||||||
|
void *(*copy)(backend_t *base, const void *image_data, const region_t *reg_visible);
|
||||||
|
|
||||||
// =========== Hooks ============
|
// =========== Hooks ============
|
||||||
/// Let the backend hook into the event handling queue
|
/// Let the backend hook into the event handling queue
|
||||||
|
|
|
@ -83,28 +83,42 @@ struct _xrender_image_data {
|
||||||
bool owned;
|
bool owned;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void compose(backend_t *base, void *img_data, int dst_x, int dst_y,
|
||||||
compose(backend_t *base, void *img_data, int dst_x, int dst_y, const region_t *reg_paint) {
|
const region_t *reg_paint, const region_t *reg_visible) {
|
||||||
struct _xrender_data *xd = (void *)base;
|
struct _xrender_data *xd = (void *)base;
|
||||||
struct _xrender_image_data *img = img_data;
|
struct _xrender_image_data *img = img_data;
|
||||||
int op = (img->has_alpha ? XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC);
|
int op = (img->has_alpha ? XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC);
|
||||||
auto alpha_pict = xd->alpha_pict[(int)(img->opacity * 255.0)];
|
auto alpha_pict = xd->alpha_pict[(int)(img->opacity * 255.0)];
|
||||||
|
region_t reg;
|
||||||
|
pixman_region32_init(®);
|
||||||
|
pixman_region32_intersect(®, (region_t *)reg_paint, (region_t *)reg_visible);
|
||||||
|
|
||||||
// Clip region of rendered_pict might be set during rendering, clear it to make
|
// Clip region of rendered_pict might be set during rendering, clear it to make
|
||||||
// sure we get everything into the buffer
|
// sure we get everything into the buffer
|
||||||
x_clear_picture_clip_region(base->c, img->pict);
|
x_clear_picture_clip_region(base->c, img->pict);
|
||||||
|
|
||||||
x_set_picture_clip_region(base->c, xd->back[xd->curr_back], 0, 0, reg_paint);
|
x_set_picture_clip_region(base->c, xd->back[xd->curr_back], 0, 0, ®);
|
||||||
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[xd->curr_back],
|
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[xd->curr_back],
|
||||||
0, 0, 0, 0, dst_x, dst_y, img->width, img->height);
|
0, 0, 0, 0, dst_x, dst_y, img->width, img->height);
|
||||||
|
pixman_region32_fini(®);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool blur(backend_t *backend_data, double opacity, const region_t *reg_paint) {
|
static bool blur(backend_t *backend_data, double opacity, const region_t *reg_blur,
|
||||||
|
const region_t *reg_visible) {
|
||||||
struct _xrender_data *xd = (void *)backend_data;
|
struct _xrender_data *xd = (void *)backend_data;
|
||||||
xcb_connection_t *c = xd->base.c;
|
xcb_connection_t *c = xd->base.c;
|
||||||
const pixman_box32_t *reg = pixman_region32_extents((region_t *)reg_paint);
|
region_t reg_op;
|
||||||
const int height = reg->y2 - reg->y1;
|
pixman_region32_init(®_op);
|
||||||
const int width = reg->x2 - reg->x1;
|
pixman_region32_intersect(®_op, (region_t *)reg_blur, (region_t *)reg_visible);
|
||||||
|
if (!pixman_region32_not_empty(®_op)) {
|
||||||
|
pixman_region32_fini(®_op);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pixman_box32_t *extent = pixman_region32_extents(®_op);
|
||||||
|
const int height = extent->y2 - extent->y1;
|
||||||
|
const int width = extent->x2 - extent->x1;
|
||||||
|
int src_x = extent->x1, src_y = extent->y1;
|
||||||
static const char *filter0 = "Nearest"; // The "null" filter
|
static const char *filter0 = "Nearest"; // The "null" filter
|
||||||
static const char *filter = "convolution";
|
static const char *filter = "convolution";
|
||||||
|
|
||||||
|
@ -116,26 +130,26 @@ static bool blur(backend_t *backend_data, double opacity, const region_t *reg_pa
|
||||||
x_create_picture_with_visual(xd->base.c, xd->base.root, width, height,
|
x_create_picture_with_visual(xd->base.c, xd->base.root, width, height,
|
||||||
xd->default_visual, 0, NULL)};
|
xd->default_visual, 0, NULL)};
|
||||||
|
|
||||||
region_t clip;
|
|
||||||
pixman_region32_init(&clip);
|
|
||||||
pixman_region32_copy(&clip, (region_t *)reg_paint);
|
|
||||||
pixman_region32_translate(&clip, -reg->x1, -reg->y1);
|
|
||||||
|
|
||||||
if (!tmp_picture[0] || !tmp_picture[1]) {
|
if (!tmp_picture[0] || !tmp_picture[1]) {
|
||||||
log_error("Failed to build intermediate Picture.");
|
log_error("Failed to build intermediate Picture.");
|
||||||
|
pixman_region32_fini(®_op);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
region_t clip;
|
||||||
|
pixman_region32_init(&clip);
|
||||||
|
pixman_region32_copy(&clip, ®_op);
|
||||||
|
pixman_region32_translate(&clip, -src_x, -src_y);
|
||||||
x_set_picture_clip_region(c, tmp_picture[0], 0, 0, &clip);
|
x_set_picture_clip_region(c, tmp_picture[0], 0, 0, &clip);
|
||||||
x_set_picture_clip_region(c, tmp_picture[1], 0, 0, &clip);
|
x_set_picture_clip_region(c, tmp_picture[1], 0, 0, &clip);
|
||||||
|
pixman_region32_fini(&clip);
|
||||||
|
|
||||||
// The multipass blur implemented here is not correct, but this is what old
|
// The multipass blur implemented here is not correct, but this is what old
|
||||||
// compton did anyway. XXX
|
// compton did anyway. XXX
|
||||||
xcb_render_picture_t src_pict = xd->back[xd->curr_back], dst_pict = tmp_picture[0];
|
xcb_render_picture_t src_pict = xd->back[xd->curr_back], dst_pict = tmp_picture[0];
|
||||||
auto alpha_pict = xd->alpha_pict[(int)(opacity * 255)];
|
auto alpha_pict = xd->alpha_pict[(int)(opacity * 255)];
|
||||||
int current = 0;
|
int current = 0;
|
||||||
int src_x = reg->x1, src_y = reg->y1;
|
x_set_picture_clip_region(c, src_pict, 0, 0, ®_op);
|
||||||
x_set_picture_clip_region(c, src_pict, 0, 0, reg_paint);
|
|
||||||
|
|
||||||
// For more than 1 pass, we do:
|
// For more than 1 pass, we do:
|
||||||
// back -(pass 1)-> tmp0 -(pass 2)-> tmp1 ...
|
// back -(pass 1)-> tmp0 -(pass 2)-> tmp1 ...
|
||||||
|
@ -162,7 +176,7 @@ static bool blur(backend_t *backend_data, double opacity, const region_t *reg_pa
|
||||||
// This is the last pass, and this is also not the first
|
// This is the last pass, and this is also not the first
|
||||||
xcb_render_composite(c, XCB_RENDER_PICT_OP_OVER, src_pict,
|
xcb_render_composite(c, XCB_RENDER_PICT_OP_OVER, src_pict,
|
||||||
alpha_pict, xd->back[xd->curr_back], 0, 0, 0,
|
alpha_pict, xd->back[xd->curr_back], 0, 0, 0,
|
||||||
0, reg->x1, reg->y1, width, height);
|
0, src_x, src_y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset filter
|
// reset filter
|
||||||
|
@ -178,12 +192,13 @@ static bool blur(backend_t *backend_data, double opacity, const region_t *reg_pa
|
||||||
// There is only 1 pass
|
// There is only 1 pass
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
xcb_render_composite(c, XCB_RENDER_PICT_OP_OVER, src_pict, alpha_pict,
|
xcb_render_composite(c, XCB_RENDER_PICT_OP_OVER, src_pict, alpha_pict,
|
||||||
xd->back[xd->curr_back], 0, 0, 0, 0, reg->x1,
|
xd->back[xd->curr_back], 0, 0, 0, 0, extent->x1, extent->y1,
|
||||||
reg->y1, width, height);
|
width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_render_free_picture(c, tmp_picture[0]);
|
xcb_render_free_picture(c, tmp_picture[0]);
|
||||||
xcb_render_free_picture(c, tmp_picture[1]);
|
xcb_render_free_picture(c, tmp_picture[1]);
|
||||||
|
pixman_region32_fini(®_op);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,16 +336,30 @@ static bool is_image_transparent(backend_t *bd, void *image) {
|
||||||
return img->has_alpha;
|
return img->has_alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void image_op(backend_t *base, enum image_operations op, void *image,
|
static bool image_op(backend_t *base, enum image_operations op, void *image,
|
||||||
const region_t *reg, void *arg) {
|
const region_t *reg_op, const region_t *reg_visible, void *arg) {
|
||||||
struct _xrender_data *xd = (void *)base;
|
struct _xrender_data *xd = (void *)base;
|
||||||
struct _xrender_image_data *img = image;
|
struct _xrender_image_data *img = image;
|
||||||
|
region_t reg;
|
||||||
double dim_opacity;
|
double dim_opacity;
|
||||||
double alpha_multiplier;
|
double alpha_multiplier;
|
||||||
|
if (op == IMAGE_OP_APPLY_ALPHA_ALL) {
|
||||||
|
alpha_multiplier = *(double *)arg;
|
||||||
|
img->opacity *= alpha_multiplier;
|
||||||
|
img->has_alpha = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixman_region32_init(®);
|
||||||
|
pixman_region32_intersect(®, (region_t *)reg_op, (region_t *)reg_visible);
|
||||||
|
if (!pixman_region32_not_empty(®)) {
|
||||||
|
pixman_region32_fini(®);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case IMAGE_OP_INVERT_COLOR:
|
case IMAGE_OP_INVERT_COLOR:
|
||||||
assert(reg);
|
x_set_picture_clip_region(base->c, img->pict, 0, 0, ®);
|
||||||
x_set_picture_clip_region(base->c, img->pict, 0, 0, reg);
|
|
||||||
if (img->has_alpha) {
|
if (img->has_alpha) {
|
||||||
auto tmp_pict =
|
auto tmp_pict =
|
||||||
x_create_picture_with_visual(base->c, base->root, img->width,
|
x_create_picture_with_visual(base->c, base->root, img->width,
|
||||||
|
@ -355,8 +384,7 @@ static void image_op(backend_t *base, enum image_operations op, void *image,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IMAGE_OP_DIM:
|
case IMAGE_OP_DIM:
|
||||||
assert(reg);
|
x_set_picture_clip_region(base->c, img->pict, 0, 0, ®);
|
||||||
x_set_picture_clip_region(base->c, img->pict, 0, 0, reg);
|
|
||||||
dim_opacity = *(double *)arg;
|
dim_opacity = *(double *)arg;
|
||||||
|
|
||||||
xcb_render_color_t color = {
|
xcb_render_color_t color = {
|
||||||
|
@ -378,19 +406,17 @@ static void image_op(backend_t *base, enum image_operations op, void *image,
|
||||||
if (alpha_multiplier == 1) {
|
if (alpha_multiplier == 1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!reg) {
|
|
||||||
img->opacity *= alpha_multiplier;
|
|
||||||
img->has_alpha = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto alpha_pict = xd->alpha_pict[(int)(alpha_multiplier * 255)];
|
auto alpha_pict = xd->alpha_pict[(int)(alpha_multiplier * 255)];
|
||||||
x_set_picture_clip_region(base->c, img->pict, 0, 0, reg);
|
x_set_picture_clip_region(base->c, img->pict, 0, 0, ®);
|
||||||
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_IN, img->pict, XCB_NONE,
|
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_IN, img->pict, XCB_NONE,
|
||||||
alpha_pict, 0, 0, 0, 0, 0, 0, img->width, img->height);
|
alpha_pict, 0, 0, 0, 0, 0, 0, img->width, img->height);
|
||||||
img->has_alpha = true;
|
img->has_alpha = true;
|
||||||
break;
|
break;
|
||||||
|
case IMAGE_OP_APPLY_ALPHA_ALL: assert(false);
|
||||||
}
|
}
|
||||||
|
pixman_region32_fini(®);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *copy(backend_t *base, const void *image, const region_t *reg) {
|
static void *copy(backend_t *base, const void *image, const region_t *reg) {
|
||||||
|
|
28
src/win.c
28
src/win.c
|
@ -137,6 +137,29 @@ void win_get_region_noframe_local(const win *w, region_t *res) {
|
||||||
|
|
||||||
gen_by_val(win_get_region_noframe_local)
|
gen_by_val(win_get_region_noframe_local)
|
||||||
|
|
||||||
|
void win_get_region_frame_local(const win *w, region_t *res) {
|
||||||
|
const margin_t extents = win_calc_frame_extents(w);
|
||||||
|
pixman_region32_fini(res);
|
||||||
|
pixman_region32_init_rects(res, (rect_t[]){
|
||||||
|
// top
|
||||||
|
{.x1 = 0, .y1 = 0, .x2 = w->g.width, .y2 = extents.top},
|
||||||
|
// bottom
|
||||||
|
{.x1 = 0, .y1 = w->g.height - extents.bottom, .x2 = w->g.width, .y2 = w->g.height},
|
||||||
|
//left
|
||||||
|
{.x1 = 0, .y1 = 0, .x2 = extents.left, .y2 = w->g.height},
|
||||||
|
// right
|
||||||
|
{.x1 = w->g.width - extents.right, .y1 = 0, .x2 = w->g.width, .y2 = w->g.height},
|
||||||
|
}, 4);
|
||||||
|
|
||||||
|
// limit the frame region to inside the window
|
||||||
|
region_t reg_win;
|
||||||
|
pixman_region32_init_rect(®_win, 0, 0, w->g.width, w->g.height);
|
||||||
|
pixman_region32_intersect(res, ®_win, res);
|
||||||
|
pixman_region32_fini(®_win);
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_by_val(win_get_region_frame_local)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a window to damaged area.
|
* Add a window to damaged area.
|
||||||
*
|
*
|
||||||
|
@ -1235,7 +1258,10 @@ void win_update_bounding_shape(session_t *ps, win *w) {
|
||||||
free(rects);
|
free(rects);
|
||||||
|
|
||||||
// Add border width because we are using a different origin.
|
// Add border width because we are using a different origin.
|
||||||
// X thinks the top left of the inner window is the origin,
|
// X thinks the top left of the inner window is the origin
|
||||||
|
// (for the bounding shape, althought xcb_get_geometry thinks
|
||||||
|
// the outer top left (outer means outside of the window
|
||||||
|
// border) is the origin),
|
||||||
// We think the top left of the border is the origin
|
// We think the top left of the border is the origin
|
||||||
pixman_region32_translate(&br, w->g.border_width, w->g.border_width);
|
pixman_region32_translate(&br, w->g.border_width, w->g.border_width);
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,8 @@ typedef enum {
|
||||||
* X goes from left to right, Y goes downwards.
|
* X goes from left to right, Y goes downwards.
|
||||||
*
|
*
|
||||||
* Global: the origin is the top left corner of the Xorg screen.
|
* Global: the origin is the top left corner of the Xorg screen.
|
||||||
* Local: the origin is the top left corner of the window, including border.
|
* Local: the origin is the top left corner of the window, border is
|
||||||
|
* considered part of the window.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Structure representing a top-level window compton manages.
|
/// Structure representing a top-level window compton manages.
|
||||||
|
@ -354,6 +355,11 @@ void add_damage_from_win(session_t *ps, win *w);
|
||||||
*/
|
*/
|
||||||
void win_get_region_noframe_local(const win *w, region_t *);
|
void win_get_region_noframe_local(const win *w, region_t *);
|
||||||
region_t win_get_region_noframe_local_by_val(const win *w);
|
region_t win_get_region_noframe_local_by_val(const win *w);
|
||||||
|
|
||||||
|
/// Get the region for the frame of the window
|
||||||
|
void win_get_region_frame_local(const win *w, region_t *res);
|
||||||
|
/// Get the region for the frame of the window, by value
|
||||||
|
region_t win_get_region_frame_local_by_val(const win *w);
|
||||||
/**
|
/**
|
||||||
* Retrieve frame extents from a window.
|
* Retrieve frame extents from a window.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue