Skip to content

Commit 090e108

Browse files
committed
fix: correctly track corner masks for floating toplevels
1 parent ca918cb commit 090e108

2 files changed

Lines changed: 77 additions & 105 deletions

File tree

TODO.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
# Effects
77
- Effects per window state (e.g. unfocused, focused, ...)
88
- Inner glow effects on borders
9-
- Floating toplevels with mica are missing rounded border clip on their surface
109
- Some layer surfaces with blur and a static position do not update the blur surface correctly (layer surface bar doesn't appear to track a toplevel behind it consistently; moving to an empty workspace from a non-empty workspace leaves behind some stale information in the blur surface)
1110
- Intel works perfectly but AMD has the following issues: gles2 non-protocol blur buffers render as black (ext-background-effect-v1 protocol, doesn't happen with mica); vulkan incorrectly clips surfaces with rounded borders, mica and shadow do not render
1211
- When shadow is enabled on a toplevel with rounded borders, the shadow seems to be clipped where the toplevel was clipped by the rounded border (either a layering or rendering issue)

src/effects.c

Lines changed: 77 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,7 +1732,66 @@ void effects_dirty_corner_masks(output_t *output) {
17321732
tl->rounded->corner_mask_dirty = true;
17331733
}
17341734

1735-
static bool rebuild_corner_masks(output_t *output, uint64_t bg_tex) {
1735+
static uint64_t capture_corner_mask_bg(output_t *output, effects_output_t *ctx, toplevel_t *tl) {
1736+
int w = output->width;
1737+
wlr_scene_output_set_position(ctx->capture_scene_output, output->lx, output->ly);
1738+
1739+
if (server.top_tree->node.enabled)
1740+
wlr_scene_node_set_enabled(&server.top_tree->node, false);
1741+
if (server.full_tree->node.enabled)
1742+
wlr_scene_node_set_enabled(&server.full_tree->node, false);
1743+
if (server.over_tree->node.enabled)
1744+
wlr_scene_node_set_enabled(&server.over_tree->node, false);
1745+
if (server.lock_tree->node.enabled)
1746+
wlr_scene_node_set_enabled(&server.lock_tree->node, false);
1747+
1748+
bool hidden = false;
1749+
if (tl->scene_tree && tl->scene_tree->node.enabled) {
1750+
wlr_scene_node_set_enabled(&tl->scene_tree->node, false);
1751+
hidden = true;
1752+
}
1753+
1754+
wlr_damage_ring_add_whole(&ctx->capture_scene_output->damage_ring);
1755+
struct wlr_output_state cap_state;
1756+
wlr_output_state_init(&cap_state);
1757+
wlr_output_state_set_enabled(&cap_state, true);
1758+
wlr_output_state_set_custom_mode(&cap_state, ctx->blur_w, ctx->blur_h, 0);
1759+
wlr_output_state_set_scale(&cap_state, (float)ctx->blur_w / (float)w);
1760+
struct wlr_scene_output_state_options opts = { .swapchain = ctx->blur_swapchain };
1761+
bool ok = wlr_scene_output_build_state(ctx->capture_scene_output, &cap_state, &opts);
1762+
1763+
if (hidden)
1764+
wlr_scene_node_set_enabled(&tl->scene_tree->node, true);
1765+
if (!server.top_tree->node.enabled)
1766+
wlr_scene_node_set_enabled(&server.top_tree->node, true);
1767+
if (!server.full_tree->node.enabled)
1768+
wlr_scene_node_set_enabled(&server.full_tree->node, true);
1769+
if (!server.over_tree->node.enabled)
1770+
wlr_scene_node_set_enabled(&server.over_tree->node, true);
1771+
if (!server.lock_tree->node.enabled)
1772+
wlr_scene_node_set_enabled(&server.lock_tree->node, true);
1773+
1774+
wlr_scene_output_set_position(ctx->capture_scene_output, -0x7fff, -0x7fff);
1775+
1776+
if (!ok || !cap_state.buffer) {
1777+
wlr_output_state_finish(&cap_state);
1778+
return 0;
1779+
}
1780+
1781+
uint64_t result = 0;
1782+
effects_backend->capture_readback(cap_state.buffer, &ctx->be_state,
1783+
ctx->be_state.pong.native_handle[0], 0, 0, ctx->blur_w, ctx->blur_h, 0, 0, ctx->blur_w,
1784+
ctx->blur_h, &result);
1785+
wlr_output_state_finish(&cap_state);
1786+
1787+
if (result) {
1788+
ctx->shared_bg_valid = false;
1789+
ctx->combined_bg_valid = false;
1790+
}
1791+
return result;
1792+
}
1793+
1794+
static bool rebuild_corner_masks(output_t *output) {
17361795
effects_output_t *ctx = output->effects;
17371796
int w = output->width, h = output->height;
17381797
bool any = false;
@@ -1766,88 +1825,9 @@ static bool rebuild_corner_masks(output_t *output, uint64_t bg_tex) {
17661825
if (content_r.width <= 0 || content_r.height <= 0)
17671826
continue;
17681827

1769-
uint64_t src;
1770-
if (bg_tex) {
1771-
src = bg_tex;
1772-
} else {
1773-
int cw = output->width, ch = output->height;
1774-
1775-
wlr_scene_output_set_position(ctx->capture_scene_output, output->lx, output->ly);
1776-
if (server.top_tree->node.enabled)
1777-
wlr_scene_node_set_enabled(&server.top_tree->node, false);
1778-
if (server.full_tree->node.enabled)
1779-
wlr_scene_node_set_enabled(&server.full_tree->node, false);
1780-
if (server.over_tree->node.enabled)
1781-
wlr_scene_node_set_enabled(&server.over_tree->node, false);
1782-
if (server.lock_tree->node.enabled)
1783-
wlr_scene_node_set_enabled(&server.lock_tree->node, false);
1784-
1785-
struct {
1786-
struct wlr_scene_node *node;
1787-
bool was;
1788-
} restore[8];
1789-
int nr = 0;
1790-
1791-
#define HIDE_IF(n) \
1792-
do { \
1793-
if ((n) && (n)->enabled) { \
1794-
restore[nr].node = (n); \
1795-
restore[nr].was = true; \
1796-
wlr_scene_node_set_enabled((n), false); \
1797-
nr++; \
1798-
} \
1799-
} while (0)
1800-
1801-
HIDE_IF(&tl->content_tree->node);
1802-
HIDE_IF(&tl->border_tree->node);
1803-
if (tl->blur) {
1804-
for (size_t bi = 0; bi < blur_count(tl->blur); bi++) {
1805-
struct wlr_scene_buffer *bnode = blur_get(tl->blur, bi);
1806-
if (bnode)
1807-
HIDE_IF(&bnode->node);
1808-
}
1809-
HIDE_IF(&tl->blur->mica_node->node);
1810-
HIDE_IF(&tl->blur->acrylic_node->node);
1811-
}
1812-
if (tl->rounded)
1813-
HIDE_IF(&tl->rounded->corner_mask_node->node);
1814-
1815-
wlr_damage_ring_add_whole(&ctx->capture_scene_output->damage_ring);
1816-
struct wlr_output_state cap_state;
1817-
wlr_output_state_init(&cap_state);
1818-
wlr_output_state_set_enabled(&cap_state, true);
1819-
wlr_output_state_set_custom_mode(&cap_state, cw, ch, 0);
1820-
struct wlr_scene_output_state_options opts = { .swapchain = ctx->full_swapchain };
1821-
bool ok = wlr_scene_output_build_state(ctx->capture_scene_output, &cap_state, &opts);
1822-
1823-
for (int i = 0; i < nr; i++)
1824-
wlr_scene_node_set_enabled(restore[i].node, true);
1825-
1826-
#undef HIDE_IF
1827-
1828-
if (!server.top_tree->node.enabled)
1829-
wlr_scene_node_set_enabled(&server.top_tree->node, true);
1830-
if (!server.full_tree->node.enabled)
1831-
wlr_scene_node_set_enabled(&server.full_tree->node, true);
1832-
if (!server.over_tree->node.enabled)
1833-
wlr_scene_node_set_enabled(&server.over_tree->node, true);
1834-
if (!server.lock_tree->node.enabled)
1835-
wlr_scene_node_set_enabled(&server.lock_tree->node, true);
1836-
wlr_scene_output_set_position(ctx->capture_scene_output, -0x7fff, -0x7fff);
1837-
1838-
if (!ok || !cap_state.buffer) {
1839-
wlr_output_state_finish(&cap_state);
1840-
continue;
1841-
}
1842-
1843-
effects_backend->capture_readback(cap_state.buffer, &ctx->be_state,
1844-
ctx->be_state.pong.native_handle[0], 0, 0, ctx->blur_w, ctx->blur_h, 0, 0, cw, ch, &src);
1845-
wlr_output_state_finish(&cap_state);
1846-
if (!src)
1847-
continue;
1848-
ctx->shared_bg_valid = false;
1849-
ctx->combined_bg_valid = false;
1850-
}
1828+
uint64_t src = capture_corner_mask_bg(output, ctx, tl);
1829+
if (!src)
1830+
continue;
18511831

18521832
if (!ensure_output_buf(&tl->rounded->corner_mask_buf, tl->rounded->corner_mask_native, w, h))
18531833
continue;
@@ -2409,16 +2389,21 @@ void effects_output_frame(output_t *output, struct wlr_scene_output *scene_outpu
24092389
}
24102390
}
24112391

2392+
// apply mica before corner masks so its bg capture (into the shared pong
2393+
// buffer) isn't invalidated by the per-window corner-mask captures
2394+
if (mica_dirty) {
2395+
uint64_t mica_bg = capture_bg_to_tex1(output, ctx, true, NULL, NULL);
2396+
if (mica_bg)
2397+
rebuild_mica(output, mica_bg);
2398+
}
2399+
24122400
// apply corner masks and blur if needed
2413-
uint64_t cm_bg_tex = 0;
24142401
if (has_layer_blur) {
24152402
if (unified) {
24162403
// single capture already blurred into blur_buf above; layers reuse it
24172404
push_blur_to_layers(output, ctx->blur_buf);
24182405
if (any_cm_dirty)
2419-
cm_bg_tex = capture_bg_to_tex1(output, ctx, true, NULL, NULL);
2420-
if (any_cm_dirty)
2421-
rebuild_corner_masks(output, cm_bg_tex);
2406+
rebuild_corner_masks(output);
24222407
push_corner_masks_to_toplevels(output, any_cm_dirty);
24232408
goto cm_done;
24242409
}
@@ -2435,32 +2420,23 @@ void effects_output_frame(output_t *output, struct wlr_scene_output *scene_outpu
24352420
push_blur_to_layers(output, ctx->layer_blur_buf);
24362421
}
24372422
if (any_cm_dirty)
2438-
cm_bg_tex = capture_bg_to_tex1(output, ctx, true, NULL, NULL);
2439-
if (any_cm_dirty)
2440-
rebuild_corner_masks(output, cm_bg_tex);
2423+
rebuild_corner_masks(output);
24412424
push_corner_masks_to_toplevels(output, any_cm_dirty);
24422425
} else if (any_layer_needs_blur) {
24432426
rebuild_live_blur_layers(output, 0, &scene_output->damage_ring.current);
24442427
push_blur_to_layers(output, ctx->layer_blur_buf);
24452428
} else if (any_cm) {
24462429
if (any_cm_dirty)
2447-
cm_bg_tex = capture_bg_to_tex1(output, ctx, true, NULL, NULL);
2448-
if (any_cm_dirty)
2449-
rebuild_corner_masks(output, cm_bg_tex);
2430+
rebuild_corner_masks(output);
24502431
push_corner_masks_to_toplevels(output, any_cm_dirty);
24512432
}
24522433
} else if (any_cm) {
24532434
if (any_cm_dirty)
2454-
cm_bg_tex = capture_bg_to_tex1(output, ctx, true, NULL, NULL);
2455-
if (any_cm_dirty)
2456-
rebuild_corner_masks(output, cm_bg_tex);
2435+
rebuild_corner_masks(output);
24572436
push_corner_masks_to_toplevels(output, any_cm_dirty);
24582437
}
24592438
cm_done:
24602439

2461-
if (mica_dirty)
2462-
rebuild_mica(output, cm_bg_tex);
2463-
24642440
if (mica_enabled && ctx->mica_buf)
24652441
push_mica_to_toplevels(output);
24662442

@@ -2526,7 +2502,6 @@ void effects_output_frame(output_t *output, struct wlr_scene_output *scene_outpu
25262502
effects_backend->frame_begin();
25272503

25282504
// apply corner masks and layer blur if needed
2529-
uint64_t cm_bg_tex_lo = 0;
25302505
if (has_layer_blur) {
25312506
bool any_layer_needs_blur = blur_enabled && layer_blur_needs_rebuild(output,
25322507
&scene_output->damage_ring.current);
@@ -2548,10 +2523,8 @@ void effects_output_frame(output_t *output, struct wlr_scene_output *scene_outpu
25482523
goto cm_bg_tex_lo_cap;
25492524
} else if (any_cm) {
25502525
cm_bg_tex_lo_cap:
2551-
if (any_cm_dirty) {
2552-
cm_bg_tex_lo = capture_bg_to_tex1(output, ctx, true, NULL, NULL);
2553-
rebuild_corner_masks(output, cm_bg_tex_lo);
2554-
}
2526+
if (any_cm_dirty)
2527+
rebuild_corner_masks(output);
25552528
push_corner_masks_to_toplevels(output, any_cm_dirty);
25562529
}
25572530

0 commit comments

Comments
 (0)