fix(pf-vdisplay/driver): report cursor_excluded adapter-wide — the declare's exclusion is not per-target
ci / web (push) Successful in 51s
ci / docs-site (push) Successful in 1m5s
apple / swift (push) Successful in 1m20s
windows-drivers / probe-and-proto (push) Successful in 1m2s
decky / build-publish (push) Successful in 28s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 21s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 16s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 11s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 8s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 10s
windows-drivers / driver-build (push) Successful in 2m23s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m5s
ci / bench (push) Successful in 6m3s
apple / screenshots (push) Successful in 6m41s
deb / build-publish (push) Successful in 12m20s
arch / build-publish (push) Successful in 12m47s
deb / build-publish-host (push) Successful in 13m7s
android / android (push) Successful in 16m14s
windows-host / package (push) Successful in 15m53s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m23s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 16m8s
ci / rust (push) Successful in 26m6s
docker / deploy-docs (push) Canceled after 25s

Field report (iPad via GameStream, 2026-07-23): cursor missing from the
stream. The session's fresh target 257 reported cursor_excluded=false
(DECLARED_TARGETS is keyed per target and only 259 had declared), so the
host skipped forced-composite — but DWM's pointer exclusion after an
IddCx hardware-cursor declare reaches EVERY later monitor of the adapter,
not just the declaring target (proven on-glass: declare on 259 under
WUDFHost 2192, then 257's frames streamed pointer-free with CURSOR_SHOWING
set and SM_MOUSEPRESENT true). GameStream/Moonlight clients cannot draw a
forwarded cursor, so those sessions were silently cursor-less.

ADD replies now report any-declare-this-WUDFHost-life (the state's real
scope — it dies with the adapter reset, same as before); per-target ids
stay only as the dbglog audit trail. Channel-less sessions on a declared
adapter then hit the existing forced-composite gate (GDI poller + blend)
and carry the pointer in-video. Host code unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 15:58:54 +02:00
co-authored by Claude Fable 5
parent 35c2c1450e
commit 248e1cbf08
4 changed files with 39 additions and 29 deletions
@@ -165,9 +165,11 @@ unsafe fn add(request: WDFREQUEST) {
// This WUDFHost's pid — where the host duplicates the sealed frame channel's handles INTO
// (`ProcessSharingDisabled`: this process is exclusively ours and dies with the device).
wudf_pid: std::process::id(),
// The target already carries an irrevocable hardware-cursor declare from an earlier
// session — a channel-less session must self-composite the pointer (§8.6 gap).
cursor_excluded: crate::monitor::target_declared(target_id) as u32,
// The ADAPTER already carries an irrevocable hardware-cursor declare from an earlier
// session — DWM's exclusion reaches every later monitor, not just the declaring target
// (on-glass 2026-07-23: declare on 259 left a fresh GameStream 257 cursor-less) — so a
// channel-less session must self-composite the pointer (§8.6 gap, adapter-wide).
cursor_excluded: crate::monitor::any_declared() as u32,
};
// Dual-size reply (the `cursor_excluded` tail ext): an un-upgraded host retrieves only the
// legacy 20-byte buffer — write the prefix it asked for instead of failing its ADD.