|
25 | 25 | #include <wlr/types/wlr_output.h> |
26 | 26 | #include <wlr/types/wlr_scene.h> |
27 | 27 | #include <wlr/util/log.h> |
| 28 | +#include <wlr/util/region.h> |
28 | 29 |
|
29 | 30 | // private wlroots functions |
30 | 31 | 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_ |
346 | 347 | ctx->height = height; |
347 | 348 | ctx->blur_w = new_bw; |
348 | 349 | ctx->blur_h = new_bh; |
| 350 | + ctx->shared_bg_valid = false; |
349 | 351 | wlr_output_state_set_custom_mode(&ctx->capture_state, width, height, 0); |
350 | 352 |
|
351 | 353 | 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 |
453 | 455 | if (w <= 0 || h <= 0) |
454 | 456 | return 0; |
455 | 457 |
|
| 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 | + |
456 | 497 | struct wl_array hidden_slide_out; |
457 | 498 | wl_array_init(&hidden_slide_out); |
458 | 499 | if (exclude_slide_out) { |
@@ -522,7 +563,10 @@ static uint64_t capture_bg_to_tex1_ex(output_t *output, effects_output_t *ctx, b |
522 | 563 | wlr_output_state_set_custom_mode(&cap_state, ctx->blur_w, ctx->blur_h, 0); |
523 | 564 | wlr_output_state_set_scale(&cap_state, (float)ctx->blur_w / (float)w); |
524 | 565 |
|
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, ®ion); |
| 568 | + else |
| 569 | + wlr_damage_ring_add_whole(&ctx->capture_scene_output->damage_ring); |
526 | 570 |
|
527 | 571 | bool ok = wlr_scene_output_build_state(ctx->capture_scene_output, &cap_state, NULL); |
528 | 572 |
|
@@ -571,11 +615,15 @@ static uint64_t capture_bg_to_tex1_ex(output_t *output, effects_output_t *ctx, b |
571 | 615 | return 0; |
572 | 616 | } |
573 | 617 |
|
574 | | - uint64_t result; |
| 618 | + uint64_t result = 0; |
575 | 619 | 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); |
577 | 622 | wlr_output_state_finish(&cap_state); |
578 | 623 |
|
| 624 | + if (result) |
| 625 | + ctx->shared_bg_valid = !mica_only && hide_blur_toplevels; |
| 626 | + |
579 | 627 | return result; |
580 | 628 | } |
581 | 629 |
|
@@ -1462,12 +1510,15 @@ static bool rebuild_corner_masks(output_t *output, uint64_t bg_tex) { |
1462 | 1510 | } |
1463 | 1511 |
|
1464 | 1512 | 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); |
1466 | 1514 | wlr_output_state_finish(&cap_state); |
1467 | 1515 | if (!src) { |
1468 | 1516 | tl->rounded->corner_mask_dirty = false; |
1469 | 1517 | continue; |
1470 | 1518 | } |
| 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; |
1471 | 1522 | } |
1472 | 1523 |
|
1473 | 1524 | 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 |
1587 | 1638 | } |
1588 | 1639 |
|
1589 | 1640 | 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); |
1592 | 1643 |
|
1593 | 1644 | wlr_buffer_unlock(ctx->capture_state.buffer); |
1594 | 1645 | ctx->capture_state.buffer = NULL; |
|
0 commit comments