new xrender: fix black border around blurred area

Similar fix to 6d646b54.

Also ping #50

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-07-07 19:49:23 +01:00
parent e62971a0c3
commit 4c460a7bd5
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
1 changed files with 35 additions and 26 deletions

View File

@ -68,6 +68,8 @@ struct _xrender_blur_context {
/// Blur kernels converted to X format /// Blur kernels converted to X format
struct x_convolution_kernel **x_blur_kernel; struct x_convolution_kernel **x_blur_kernel;
int resize_width, resize_height;
/// Number of blur kernels /// Number of blur kernels
int x_blur_kernel_count; int x_blur_kernel_count;
}; };
@ -144,19 +146,22 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
return true; return true;
} }
const pixman_box32_t *extent = pixman_region32_extents(&reg_op); region_t reg_op_resized =
const auto height = to_u16_checked(extent->y2 - extent->y1); resize_region(&reg_op, bctx->resize_width, bctx->resize_height);
const auto width = to_u16_checked(extent->x2 - extent->x1);
const pixman_box32_t *extent_resized = pixman_region32_extents(&reg_op_resized);
const auto height_resized = to_u16_checked(extent_resized->y2 - extent_resized->y1);
const auto width_resized = to_u16_checked(extent_resized->x2 - extent_resized->x1);
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";
// Create a buffer for storing blurred picture, make it just big enough // Create a buffer for storing blurred picture, make it just big enough
// for the blur region // for the blur region
xcb_render_picture_t tmp_picture[2] = { xcb_render_picture_t tmp_picture[2] = {
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_resized,
xd->default_visual, 0, NULL), height_resized, xd->default_visual, 0, NULL),
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_resized,
xd->default_visual, 0, NULL)}; height_resized, xd->default_visual, 0, NULL)};
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.");
@ -166,18 +171,16 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
region_t clip; region_t clip;
pixman_region32_init(&clip); pixman_region32_init(&clip);
pixman_region32_copy(&clip, &reg_op); pixman_region32_copy(&clip, &reg_op_resized);
pixman_region32_translate(&clip, -extent->x1, -extent->y1); pixman_region32_translate(&clip, -extent_resized->x1, -extent_resized->y1);
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); pixman_region32_fini(&clip);
// The multipass blur implemented here is not correct, but this is what old
// 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 * MAX_ALPHA)]; auto alpha_pict = xd->alpha_pict[(int)(opacity * MAX_ALPHA)];
int current = 0; int current = 0;
x_set_picture_clip_region(c, src_pict, 0, 0, &reg_op); x_set_picture_clip_region(c, src_pict, 0, 0, &reg_op_resized);
// 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 ...
@ -189,7 +192,6 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
// Copy from source picture to destination. The filter must // Copy from source picture to destination. The filter must
// be applied on source picture, to get the nearby pixels outside the // be applied on source picture, to get the nearby pixels outside the
// window. // window.
// TODO cache converted blur_kerns
xcb_render_set_picture_filter(c, src_pict, to_u16_checked(strlen(filter)), xcb_render_set_picture_filter(c, src_pict, to_u16_checked(strlen(filter)),
filter, filter,
to_u32_checked(bctx->x_blur_kernel[i]->size), to_u32_checked(bctx->x_blur_kernel[i]->size),
@ -197,22 +199,26 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
if (i == 0) { if (i == 0) {
// First pass, back buffer -> tmp picture // First pass, back buffer -> tmp picture
// (we do this even if this is also the last pass) // (we do this even if this is also the last pass, because we
// cannot do back buffer -> back buffer)
xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE,
dst_pict, to_i16_checked(extent->x1), dst_pict, to_i16_checked(extent_resized->x1),
to_i16_checked(extent->y1), 0, 0, 0, 0, to_i16_checked(extent_resized->y1), 0, 0, 0,
width, height); 0, width_resized, height_resized);
} else if (i < bctx->x_blur_kernel_count - 1) { } else if (i < bctx->x_blur_kernel_count - 1) {
// This is not the last pass or the first pass, // This is not the last pass or the first pass,
// tmp picture 1 -> tmp picture 2 // tmp picture 1 -> tmp picture 2
xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict,
dst_pict, 0, 0, 0, 0, 0, 0, width, height); XCB_NONE, dst_pict, 0, 0, 0, 0, 0, 0,
width_resized, height_resized);
} else { } else {
x_set_picture_clip_region(c, xd->back[xd->curr_back], 0, 0, &reg_op);
// This is the last pass, and we are doing more than 1 pass // This is the last pass, and we are doing more than 1 pass
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, to_i16_checked(extent->x1), 0, to_i16_checked(extent_resized->x1),
to_i16_checked(extent->y1), width, height); to_i16_checked(extent_resized->y1),
width_resized, height_resized);
} }
// reset filter // reset filter
@ -226,10 +232,11 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
// 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, x_set_picture_clip_region(c, xd->back[xd->curr_back], 0, 0, &reg_op);
xd->back[xd->curr_back], 0, 0, 0, 0, xcb_render_composite(
to_i16_checked(extent->x1), c, XCB_RENDER_PICT_OP_OVER, src_pict, alpha_pict,
to_i16_checked(extent->y1), width, height); xd->back[xd->curr_back], 0, 0, 0, 0, to_i16_checked(extent_resized->x1),
to_i16_checked(extent_resized->y1), width_resized, height_resized);
} }
xcb_render_free_picture(c, tmp_picture[0]); xcb_render_free_picture(c, tmp_picture[0]);
@ -478,7 +485,7 @@ static void *copy(backend_t *base, const void *image, const region_t *reg) {
} }
void *create_blur_context(backend_t *base, enum blur_method method, void *args) { void *create_blur_context(backend_t *base, enum blur_method method, void *args) {
auto ret = cmalloc(struct _xrender_blur_context); auto ret = ccalloc(1, struct _xrender_blur_context);
if (!method || method >= BLUR_METHOD_INVALID) { if (!method || method >= BLUR_METHOD_INVALID) {
ret->method = BLUR_METHOD_NONE; ret->method = BLUR_METHOD_NONE;
return ret; return ret;
@ -499,6 +506,8 @@ void *create_blur_context(backend_t *base, enum blur_method method, void *args)
int center = kernels[i]->h * kernels[i]->w / 2; int center = kernels[i]->h * kernels[i]->w / 2;
x_create_convolution_kernel(kernels[i], kernels[i]->data[center], x_create_convolution_kernel(kernels[i], kernels[i]->data[center],
&ret->x_blur_kernel[i]); &ret->x_blur_kernel[i]);
ret->resize_width += kernels[i]->w / 2;
ret->resize_height += kernels[i]->h / 2;
} }
ret->x_blur_kernel_count = kernel_count; ret->x_blur_kernel_count = kernel_count;