Skip to content

Commit

Permalink
backend/xrender: be less clever with blur passes
Browse files Browse the repository at this point in the history
We used to use the target picture as the render target for the last blur
pass, instead of an intermediate picture. This saves a Composite requests.

With this commit, all blur passes are rendered into intermediate
pictures. Then the final blur result is composited into the target. This
is less efficient, but since blur is *essentially* non-functionaly on
xrender (unless you use xf86-video-intel), we can't make it much worse.

This is a preparation for implementing our own accelerated blur on the
xrender backend.

Signed-off-by: Yuxuan Shui <[email protected]>
  • Loading branch information
yshui committed Oct 11, 2024
1 parent 6caa76a commit 729ea65
Showing 1 changed file with 18 additions and 33 deletions.
51 changes: 18 additions & 33 deletions src/backend/xrender/xrender.c
Original file line number Diff line number Diff line change
Expand Up @@ -583,39 +583,26 @@ static bool xrender_blur(struct backend_base *base, ivec2 origin,

// For more than 1 pass, we do:
// source -(pass 1)-> tmp0 -(pass 2)-> tmp1 ...
// -(pass n-1)-> tmp0 or tmp1 -(pass n)-> target
// -(pass n)-> tmp0 or tmp1 -(composite)-> target
// For 1 pass, we do:
// (if source == target)
// source -(pass 1)-> tmp0 -(copy)-> target
// (if source != target)
// source -(pass 1)-> target
xcb_render_picture_t dst_pict = target == source ? tmp_picture[0] : target->pict;
// source -(pass 1)-> tmp0 -(composite)-> target
xcb_render_picture_t dst_pict = tmp_picture[0];
ivec2 src_origin = {.x = extent_resized->x1, .y = extent_resized->y1};
ivec2 dst_origin = {};
int npasses = bctx->x_blur_kernel_count;
if (source == target && npasses == 1) {
npasses = 2;
}
for (int i = 0; i < npasses; i++) {
// Copy from source picture to destination. The filter must
// be applied on source picture, to get the nearby pixels outside the
// window.
xcb_render_picture_t pass_mask_pict =
dst_pict == target->pict ? mask_pict : XCB_NONE;
const uint8_t op = dst_pict == target->pict ? XCB_RENDER_PICT_OP_OVER
: XCB_RENDER_PICT_OP_SRC;
if (i < bctx->x_blur_kernel_count) {
xcb_render_set_picture_filter(
c->c, src_pict, to_u16_checked(strlen(filter)), filter,
to_u32_checked(bctx->x_blur_kernel[i]->size),
bctx->x_blur_kernel[i]->kernel);
}
xcb_render_set_picture_filter(c->c, src_pict,
to_u16_checked(strlen(filter)), filter,
to_u32_checked(bctx->x_blur_kernel[i]->size),
bctx->x_blur_kernel[i]->kernel);

// clang-format off
xcb_render_composite(c->c, op, src_pict, pass_mask_pict, dst_pict,
xcb_render_composite(c->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, dst_pict,
to_i16_checked(src_origin.x) , to_i16_checked(src_origin.y),
to_i16_checked(-mask_pict_origin.x) , to_i16_checked(-mask_pict_origin.y),
to_i16_checked(dst_origin.x) , to_i16_checked(dst_origin.y),
0 , 0 ,
0 , 0 ,
width_resized , height_resized);
// clang-format on

Expand All @@ -625,19 +612,17 @@ static bool xrender_blur(struct backend_base *base, ivec2 origin,

auto next_tmp = src_pict == source->pict ? tmp_picture[1] : src_pict;
src_pict = dst_pict;
if (i + 1 == npasses - 1) {
// Intermediary to target
dst_pict = target->pict;
dst_origin = (ivec2){.x = origin.x + extent_resized->x1,
.y = origin.y + extent_resized->y1};
} else {
// Intermediary to intermediary
dst_pict = next_tmp;
dst_origin = (ivec2){.x = 0, .y = 0};
}
dst_pict = next_tmp;
src_origin = (ivec2){.x = 0, .y = 0};
}

// Finally, we composite the last pass to the target picture
xcb_render_composite(
c->c, XCB_RENDER_PICT_OP_OVER, src_pict, mask_pict, target->pict, 0, 0,
to_i16_checked(-mask_pict_origin.x), to_i16_checked(-mask_pict_origin.y),
to_i16_checked(origin.x + extent_resized->x1),
to_i16_checked(origin.y + extent_resized->y1), width_resized, height_resized);

if (mask_allocated) {
x_free_picture(c, mask_pict);
}
Expand Down

0 comments on commit 729ea65

Please sign in to comment.