From 9db4841ce4f530345e58d6f42485204aa3979a95 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Wed, 22 Jul 2026 16:18:05 +0200 Subject: [PATCH] fix(linux/capture): cursor meta size range must cover Mutter's fixed 384x384 offer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mutter offers SPA_META_Cursor with a FIXED size pod — SPA_POD_Int(CURSOR_META_SIZE(384, 384)) in meta-screen-cast-stream-src.c — while our request capped the range at meta_size(256, 256). The intersection is empty, so the Meta param silently failed to negotiate and no buffer ever carried the meta region: the entire Linux cursor pipeline (forward AND blend) was blind on GNOME, proven by an on-glass probe counting 32k+ buffers with zero metas. KWin's offer fits inside 256², which is why the same consumer code passed there. Raise the max to 1024² headroom (the negotiated allocation follows the producer's value, not our max) and align the bitmap parse guard. Co-Authored-By: Claude Fable 5 --- crates/pf-capture/src/linux/mod.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/pf-capture/src/linux/mod.rs b/crates/pf-capture/src/linux/mod.rs index 40ce1862..ba3f4fa0 100644 --- a/crates/pf-capture/src/linux/mod.rs +++ b/crates/pf-capture/src/linux/mod.rs @@ -1323,10 +1323,17 @@ mod pipewire { value: pw::spa::pod::Value::Choice(pw::spa::pod::ChoiceValue::Int( pw::spa::utils::Choice( pw::spa::utils::ChoiceFlags::empty(), + // The max must cover the producer's offer or the Meta param silently + // fails to negotiate and NO buffer ever carries the meta region: + // Mutter offers a FIXED `SPA_POD_Int(CURSOR_META_SIZE(384, 384))` + // (meta-screen-cast-stream-src.c, GNOME 50) — a 256² max made the + // intersection empty, which cost the whole Linux cursor channel + // on-glass. 1024² is headroom, not an allocation: the negotiated + // region follows the producer's value. pw::spa::utils::ChoiceEnum::Range { default: meta_size(64, 64), min: meta_size(1, 1), - max: meta_size(256, 256), + max: meta_size(1024, 1024), }, ), )), @@ -1444,8 +1451,9 @@ mod pipewire { (*bmp).offset as usize, ) }; - // Ignore empty or implausibly large bitmaps (we requested <= 256×256). - if bw == 0 || bh == 0 || bw > 256 || bh > 256 { + // Ignore empty or implausibly large bitmaps (the meta-size request covers <= 1024×1024; + // real cursors are ≤96px — the cursor channel downscales >120px for the wire anyway). + if bw == 0 || bh == 0 || bw > 1024 || bh > 1024 { return; } let row = bw as usize * 4;