srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2025-08-13 20:10:00 +0200
committersrdusr <[email protected]>2025-08-13 20:10:00 +0200
commit6694a2d9946d98d5752d84b22c45879cab5c9abe (patch)
tree49fcbeec0c06573400195eadfdc9bfb222d9c8fd /crates
parent7f4740046a004a1ad06aefa5d1d6b1a351571b1a (diff)
downloadsrdwm-6694a2d9946d98d5752d84b22c45879cab5c9abe.tar.gz
srdwm-6694a2d9946d98d5752d84b22c45879cab5c9abe.zip
Fix terminal content disappearing on resize: don't cache a blank content mask
Reported live: "terminal output/everything disappears when i sometimes resize terminal." masked_content_buffer (the udev/Pixman rounded-corner content-masking path, live on this machine via general.rounded_corners) rendered a window's whole surface tree into an off-screen buffer and returned Some(bytes) unconditionally, with no check for whether that tree actually produced any drawable elements. content_epoch bumps on every commit, and a fast interactive resize is a rapid-fire sequence of commits - real odds that one races ahead of the client's own texture import, making the off-screen render legitimately come back empty. That blank result got returned as Some and cached under the new epoch the same as a correct one would, and rounded_content_buffer only rebuilds on the next epoch change - so the blank buffer stayed on screen, fully transparent, until the window's next real content change, indefinite for an idle terminal. masked_content_buffer now returns None when the element tree is empty, before doing the render+readback at all - the same "give up unmasked" pattern already used for a genuine renderer error. rounded_content_buffer drops rather than replaces its cache entry on None, so the render loop falls back to unmasked content for that one frame and retries the masked path on the next. Scoped to the udev/Pixman backend; winit masks via a GLES shader with no equivalent failure mode.
Diffstat (limited to 'crates')
-rw-r--r--crates/wayland/src/rounded_corners_pixman.rs24
1 files changed, 24 insertions, 0 deletions
diff --git a/crates/wayland/src/rounded_corners_pixman.rs b/crates/wayland/src/rounded_corners_pixman.rs
index 808d0fe..a0126fe 100644
--- a/crates/wayland/src/rounded_corners_pixman.rs
+++ b/crates/wayland/src/rounded_corners_pixman.rs
@@ -92,6 +92,30 @@ pub(crate) fn masked_content_buffer(renderer: &mut PixmanRenderer, surface: &WlS
// transparency so the border/desktop already drawn underneath on the
// real output shows through there, not a solid black patch.
let elements = render_elements_from_surface_tree::<_, crate::elements::OverlayElement<PixmanRenderer>>(renderer, surface, loc, 1.0, 1.0, Kind::Unspecified);
+ // An empty tree here is not trusted as "this window genuinely has no
+ // content" - it's indistinguishable from a transient race where a
+ // commit has already bumped `content_epoch` (every commit does,
+ // unconditionally) but the surface's own texture import hasn't caught
+ // up yet, real and reachable during a fast resize's rapid-fire commits.
+ // `rounded_content_buffer`'s cache keys purely on `epoch`/`radius`/
+ // `loc`/`size`, not on content, so a blank render returned as `Some`
+ // here would get cached as this window's current, correct content --
+ // and then persist on screen, fully transparent, until the *next*
+ // epoch-bumping commit, which for an idle/settled terminal can be a
+ // long wait. Reported live as a terminal's content disappearing
+ // entirely on some resizes. Returning `None` instead makes the caller
+ // treat this the same as any other failed render: `rounded_content_
+ // buffer` drops any cached entry rather than replacing it with this
+ // blank one, and the render loop falls back to the ordinary unmasked
+ // `surface_content_elements` path for this one frame - which shows
+ // the window's real content (square corners for a frame, not blank),
+ // and naturally retries the masked path again next frame since the
+ // dropped cache entry reads as stale again with nothing to compare
+ // against.
+ if elements.is_empty() {
+ log::debug!("rounded_corners_pixman: masked_content_buffer: surface tree had no drawable elements - giving up unmasked this frame");
+ return None;
+ }
let mut target = match renderer.create_buffer(Fourcc::Argb8888, (w, h).into()) {
Ok(t) => t,
Err(e) => {