Skip to content

Commit cab5c1f

Browse files
committed
perf: skip capture when only blurred-window content changes
1 parent dbe9e1f commit cab5c1f

5 files changed

Lines changed: 75 additions & 17 deletions

File tree

include/effects.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ typedef struct effects_output_t {
7878

7979
uint64_t cached_bg_tex;
8080
bool bg_cache_valid;
81+
82+
// true when pong holds the shared backdrop (i.e. the last capture was a
83+
// full/shared capture); allows region-based re-capture instead of whole
84+
bool shared_bg_valid;
8185
} effects_output_t;
8286

8387
typedef struct effects_state_t {

include/effects_backend.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ typedef struct effects_backend_t {
152152
struct be_screen_shader_params *p);
153153

154154
bool (*capture_readback)(struct wlr_buffer *capture_buffer, be_output_state_t *state,
155-
uint64_t dst_fbo, int dst_w, int dst_h, int src_w, int src_h, uint64_t *out_tex);
155+
uint64_t dst_fbo, int dst_x, int dst_y, int dst_w, int dst_h, int src_x, int src_y, int src_w,
156+
int src_h, uint64_t *out_tex);
156157

157158
const char *(*get_screen_shader_source)(const char *name);
158159
bool (*compile_screen_shader)(const char *frag_src);

src/effects.c

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <wlr/types/wlr_output.h>
2626
#include <wlr/types/wlr_scene.h>
2727
#include <wlr/util/log.h>
28+
#include <wlr/util/region.h>
2829

2930
// private wlroots functions
3031
extern bool wlr_renderer_is_pixman(const struct wlr_renderer *wlr_renderer);
@@ -346,6 +347,7 @@ void effects_output_resize(effects_output_t *ctx, int width, int height, output_
346347
ctx->height = height;
347348
ctx->blur_w = new_bw;
348349
ctx->blur_h = new_bh;
350+
ctx->shared_bg_valid = false;
349351
wlr_output_state_set_custom_mode(&ctx->capture_state, width, height, 0);
350352

351353
effects_destroy_buffer(&ctx->mica_buf, ctx->mica_native);
@@ -453,6 +455,45 @@ static uint64_t capture_bg_to_tex1_ex(output_t *output, effects_output_t *ctx, b
453455
if (w <= 0 || h <= 0)
454456
return 0;
455457

458+
// Re-capture only the damaged area at blur resolution instead of the whole
459+
// frame: the backdrop texture (pong) keeps its previous content everywhere
460+
// else. Damage that only touches the inside of blurred windows (which are
461+
// hidden during the capture) still re-renders their rects, but at blur
462+
// resolution that is far cheaper than a full-frame capture.
463+
struct wlr_box region = {
464+
0,
465+
0,
466+
ctx->blur_w,
467+
ctx->blur_h
468+
};
469+
bool region_capture = false;
470+
// only the shared backdrop capture (all blur toplevels/layer surfaces hidden)
471+
// produces content compatible with the existing pong content
472+
if (!exclude_slide_out && !mica_only && hide_blur_toplevels && ctx->shared_bg_valid) {
473+
struct wlr_scene_output *real_so = wlr_scene_get_scene_output(server.scene, output->wlr_output);
474+
if (real_so && !pixman_region32_empty(&real_so->damage_ring.current)) {
475+
pixman_region32_copy(&ctx->scratch_region_a, &real_so->damage_ring.current);
476+
wlr_region_scale_xy(&ctx->scratch_region_a, &ctx->scratch_region_a, (float)ctx->blur_w / (float)w,
477+
(float)ctx->blur_h / (float)h);
478+
pixman_region32_intersect_rect(&ctx->scratch_region_a, &ctx->scratch_region_a, 0, 0, ctx->blur_w,
479+
ctx->blur_h);
480+
if (!pixman_region32_empty(&ctx->scratch_region_a)) {
481+
pixman_box32_t *ext = pixman_region32_extents(&ctx->scratch_region_a);
482+
region = (struct wlr_box){
483+
ext->x1,
484+
ext->y1,
485+
ext->x2 - ext->x1,
486+
ext->y2 - ext->y1
487+
};
488+
region_capture = true;
489+
}
490+
}
491+
if (!region_capture) {
492+
wlr_scene_output_set_position(ctx->capture_scene_output, -0x7fff, -0x7fff);
493+
return ctx->be_state.pong.native_handle[1];
494+
}
495+
}
496+
456497
struct wl_array hidden_slide_out;
457498
wl_array_init(&hidden_slide_out);
458499
if (exclude_slide_out) {
@@ -522,7 +563,10 @@ static uint64_t capture_bg_to_tex1_ex(output_t *output, effects_output_t *ctx, b
522563
wlr_output_state_set_custom_mode(&cap_state, ctx->blur_w, ctx->blur_h, 0);
523564
wlr_output_state_set_scale(&cap_state, (float)ctx->blur_w / (float)w);
524565

525-
wlr_damage_ring_add_whole(&ctx->capture_scene_output->damage_ring);
566+
if (region_capture)
567+
wlr_damage_ring_add_box(&ctx->capture_scene_output->damage_ring, &region);
568+
else
569+
wlr_damage_ring_add_whole(&ctx->capture_scene_output->damage_ring);
526570

527571
bool ok = wlr_scene_output_build_state(ctx->capture_scene_output, &cap_state, NULL);
528572

@@ -571,11 +615,15 @@ static uint64_t capture_bg_to_tex1_ex(output_t *output, effects_output_t *ctx, b
571615
return 0;
572616
}
573617

574-
uint64_t result;
618+
uint64_t result = 0;
575619
effects_backend->capture_readback(cap_state.buffer, &ctx->be_state,
576-
ctx->be_state.pong.native_handle[0], ctx->blur_w, ctx->blur_h, ctx->blur_w, ctx->blur_h, &result);
620+
ctx->be_state.pong.native_handle[0], region.x, region.y, region.width, region.height, region.x,
621+
region.y, region.width, region.height, &result);
577622
wlr_output_state_finish(&cap_state);
578623

624+
if (result)
625+
ctx->shared_bg_valid = !mica_only && hide_blur_toplevels;
626+
579627
return result;
580628
}
581629

@@ -1462,12 +1510,15 @@ static bool rebuild_corner_masks(output_t *output, uint64_t bg_tex) {
14621510
}
14631511

14641512
effects_backend->capture_readback(cap_state.buffer, &ctx->be_state,
1465-
ctx->be_state.pong.native_handle[0], ctx->blur_w, ctx->blur_h, cw, ch, &src);
1513+
ctx->be_state.pong.native_handle[0], 0, 0, ctx->blur_w, ctx->blur_h, 0, 0, cw, ch, &src);
14661514
wlr_output_state_finish(&cap_state);
14671515
if (!src) {
14681516
tl->rounded->corner_mask_dirty = false;
14691517
continue;
14701518
}
1519+
// this capture overwrites pong with the corner-mask backdrop
1520+
// (blur output nodes hidden), so the shared backdrop is stale
1521+
ctx->shared_bg_valid = false;
14711522
}
14721523

14731524
if (!ensure_output_buf(&tl->rounded->corner_mask_buf, tl->rounded->corner_mask_native, w, h)) {
@@ -1587,8 +1638,8 @@ static uint64_t capture_full_scene_to_tex(output_t *output, effects_output_t *ct
15871638
}
15881639

15891640
uint64_t result;
1590-
effects_backend->capture_readback(ctx->capture_state.buffer, &ctx->be_state, screen_fbo, w, h, w, h,
1591-
&result);
1641+
effects_backend->capture_readback(ctx->capture_state.buffer, &ctx->be_state, screen_fbo, 0, 0, w, h,
1642+
0, 0, w, h, &result);
15921643

15931644
wlr_buffer_unlock(ctx->capture_state.buffer);
15941645
ctx->capture_state.buffer = NULL;

src/effects_gles2.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -963,7 +963,8 @@ static bool gles2_apply_screen_shader(uint64_t src_tex, uint64_t dst_fbo, int w,
963963
}
964964

965965
static bool gles2_capture_readback(struct wlr_buffer *capture_buffer, be_output_state_t *state,
966-
uint64_t dst_fbo, int dst_w, int dst_h, int src_w, int src_h, uint64_t *out_tex) {
966+
uint64_t dst_fbo, int dst_x, int dst_y, int dst_w, int dst_h, int src_x, int src_y, int src_w,
967+
int src_h, uint64_t *out_tex) {
967968
GLuint capture_fbo = wlr_gles2_renderer_get_buffer_fbo(g->renderer, capture_buffer);
968969
if (!capture_fbo) {
969970
wlr_log(WLR_INFO, "gles2: capture_readback: no FBO");
@@ -984,7 +985,7 @@ static bool gles2_capture_readback(struct wlr_buffer *capture_buffer, be_output_
984985

985986
if (attach_type == GL_TEXTURE && attach_name > 0 && g->prog_ext_blit) {
986987
glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)dst_fbo);
987-
glViewport(0, 0, dst_w, dst_h);
988+
glViewport(dst_x, dst_y, dst_w, dst_h);
988989
glActiveTexture(GL_TEXTURE0);
989990
glBindTexture(GL_TEXTURE_EXTERNAL_OES, (GLuint)attach_name);
990991
glUseProgram(g->prog_ext_blit);
@@ -996,7 +997,7 @@ static bool gles2_capture_readback(struct wlr_buffer *capture_buffer, be_output_
996997
result_tex = (GLuint)state->screen_shader.native_handle[1];
997998
} else if (attach_type == GL_TEXTURE && attach_name > 0) {
998999
glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)dst_fbo);
999-
glViewport(0, 0, dst_w, dst_h);
1000+
glViewport(dst_x, dst_y, dst_w, dst_h);
10001001
glActiveTexture(GL_TEXTURE0);
10011002
glBindTexture(GL_TEXTURE_2D, (GLuint)attach_name);
10021003
glUseProgram(g->prog_blit);
@@ -1025,11 +1026,11 @@ static bool gles2_capture_readback(struct wlr_buffer *capture_buffer, be_output_
10251026

10261027
glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo);
10271028
glBindTexture(GL_TEXTURE_2D, staging_tex);
1028-
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, src_w, src_h);
1029+
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, src_x, src_y, src_w, src_h);
10291030
glBindFramebuffer(GL_FRAMEBUFFER, 0);
10301031

10311032
glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)dst_fbo);
1032-
glViewport(0, 0, dst_w, dst_h);
1033+
glViewport(dst_x, dst_y, dst_w, dst_h);
10331034
glActiveTexture(GL_TEXTURE0);
10341035
glBindTexture(GL_TEXTURE_2D, staging_tex);
10351036
glUseProgram(g->prog_blit);

src/effects_vk.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2071,7 +2071,8 @@ static bool vk_apply_screen_shader(uint64_t src_tex, uint64_t dst_fbo, int w, in
20712071
}
20722072

20732073
static bool vk_capture_readback(struct wlr_buffer *capture_buffer, be_output_state_t *state,
2074-
uint64_t dst_fbo, int dst_w, int dst_h, int src_w, int src_h, uint64_t *out_tex) {
2074+
uint64_t dst_fbo, int dst_x, int dst_y, int dst_w, int dst_h, int src_x, int src_y, int src_w,
2075+
int src_h, uint64_t *out_tex) {
20752076
vk->frame_dirty = true;
20762077
vk_ensure_cb_begun();
20772078
(void)src_w;
@@ -2130,13 +2131,13 @@ static bool vk_capture_readback(struct wlr_buffer *capture_buffer, be_output_sta
21302131
VkImageBlit region = {
21312132
.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
21322133
.srcOffsets = {
2133-
{0, 0, 0},
2134-
{capture_w, capture_h, 1}
2134+
{src_x, src_y, 0},
2135+
{src_x + capture_w, src_y + capture_h, 1}
21352136
},
21362137
.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
21372138
.dstOffsets = {
2138-
{0, 0, 0},
2139-
{dst_w, dst_h, 1}
2139+
{dst_x, dst_y, 0},
2140+
{dst_x + dst_w, dst_y + dst_h, 1}
21402141
},
21412142
};
21422143
vkCmdBlitImage(vk->frame_cb, vk_attribs.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->img.image,

0 commit comments

Comments
 (0)