feat(windows): IddCx hardware-cursor channel — remote-desktop sweep M2c
Brings the cursor channel to Windows hosts. The pf-vdisplay driver declares an IddCx hardware cursor for sessions that negotiated cursor-forward — DWM then EXCLUDES the pointer from the IDD frame and delivers shape/position out-of-band, into the same CursorOverlay → forwarder → wire → client pipeline the Linux portal path uses. - pf-driver-proto v5 (additive, host floor stays 3): AddRequest's spare tail becomes hw_cursor (same size/offsets); IOCTL_SET_CURSOR_CHANNEL delivers a host-created CursorShm section (64-byte seqlock header + 256² shape buffer, layout pinned + tested). No event crosses the boundary — the host polls at encode-tick pace. - driver: wdk-iddcx grows the two cursor DDI wrappers; a per-monitor cursor worker (event wait → QueryHardwareCursor → seqlock publish) starts only when BOTH the ADD asked and the channel arrived, so a failed delivery leaves DWM compositing as today. Shape bytes ship raw (BGRA/masked + pitch); the host converts. - host: the section rides the existing sealed-channel broker (least- privilege dup, remote reap on failure); IddPushCapturer::cursor() seqlock-reads → CursorOverlay (BGRA→RGBA, masked-color approximation, desktop→frame origin shift, per-shape conversion cache). New Capturer::cursor() trait hook — the encode loop prefers it over the frame-attached overlay because hardware-cursor moves produce NO new frame on a static desktop. hw_cursor survives the re-arrival resize (carried on the manager's Monitor). - negotiation: cursor_forward grows the Windows arm (client cap ∧ driver proto ≥ 5, probed once via the control device); SessionPlan carries cursor_forward → OutputFormat.hw_cursor. - drive-by: wdk-probe's two pre-existing same-type casts (clippy) and pf-vdisplay's stale spike-test refs (crate::win_display moved to pf-win-display; tracing-subscriber was never a dep) repaired. Verified: proto tests on Mac AND MSVC (15/15 incl. the CursorShm layout pin); clippy -D warnings for proto/frame/capture/vdisplay/host on Linux (.21) and native Windows (.173); the DRIVER workspace clippy -D warnings green against the real WDK 10.0.26100 bindgen (DDI names, enum variants and IDARG layouts all bind). On-box driver deploy + on-glass validation follow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -69,6 +69,15 @@ pub trait Capturer: Send {
|
||||
/// SDR / a backend that doesn't expose it (the default — Linux capture has no HDR path yet).
|
||||
/// The stream loop forwards this to the encoder (in-band SEI) and the client (`0xCE` datagram),
|
||||
/// so the two stay a single source of truth. May change mid-session if the source is regraded.
|
||||
/// The capture source's LIVE cursor state, when it arrives out-of-band from the frames
|
||||
/// (the Windows IddCx hardware-cursor channel). Polled by the encode loop every tick and
|
||||
/// preferred over `CapturedFrame::cursor` — with a hardware cursor, pointer-only moves
|
||||
/// produce NO new frame, so the frame-attached overlay would go stale on a static desktop.
|
||||
/// Default `None`: the Linux portal path attaches its cursor to frames instead.
|
||||
fn cursor(&mut self) -> Option<pf_frame::CursorOverlay> {
|
||||
None
|
||||
}
|
||||
|
||||
fn hdr_meta(&self) -> Option<punktfunk_core::quic::HdrMeta> {
|
||||
None
|
||||
}
|
||||
@@ -367,6 +376,16 @@ pub type FrameChannelSender = std::sync::Arc<
|
||||
dyn Fn(&pf_driver_proto::control::SetFrameChannelRequest) -> Result<()> + Send + Sync,
|
||||
>;
|
||||
|
||||
/// Delivery closure for the v5 hardware-cursor channel (`IOCTL_SET_CURSOR_CHANNEL`) — same
|
||||
/// facade contract as [`FrameChannelSender`]. `Some` also OPTS THE SESSION IN: the capturer
|
||||
/// creates + delivers the cursor section only when the host hands it a sender (the negotiated
|
||||
/// cursor-forward sessions), and the driver only declares the hardware cursor once that
|
||||
/// delivery lands — so a plain session keeps DWM's composited pointer untouched.
|
||||
#[cfg(target_os = "windows")]
|
||||
pub type CursorChannelSender = std::sync::Arc<
|
||||
dyn Fn(&pf_driver_proto::control::SetCursorChannelRequest) -> Result<()> + Send + Sync,
|
||||
>;
|
||||
|
||||
// One-time PipeWire library init, shared by the video (portal) and audio capture threads.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod pwinit;
|
||||
@@ -450,6 +469,7 @@ pub fn open_idd_push(
|
||||
pyrowave: bool,
|
||||
keepalive: Box<dyn Send>,
|
||||
sender: FrameChannelSender,
|
||||
cursor_sender: Option<CursorChannelSender>,
|
||||
) -> std::result::Result<Box<dyn Capturer>, (anyhow::Error, Box<dyn Send>)> {
|
||||
idd_push::IddPushCapturer::open(
|
||||
target,
|
||||
@@ -459,6 +479,7 @@ pub fn open_idd_push(
|
||||
pyrowave,
|
||||
keepalive,
|
||||
sender,
|
||||
cursor_sender,
|
||||
)
|
||||
.map(|c| Box::new(c) as Box<dyn Capturer>)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user