feat(vdisplay): compositor-embedded pointer for sessions without the cursor channel (Phase B)
Since the cursor-channel work, every Linux virtual output was created in metadata pointer mode — making ALL sessions depend on host-side cursor compositing, including the ones that can never use the channel (Moonlight/ GameStream, legacy clients, capture-mode starts). Those sessions paid the blend bring-up per session and, whenever a visible cursor was composited, the loss of NVENC's stream-ordered submit — for a strictly worse cursor than the compositor's own. Mirror the Windows no-regression gate: the already-wired per-session set_hw_cursor(cursor_forward) now drives the Linux backends too. A cursor-channel session gets metadata (shapes forwarded, composite flip blends host-side — today's validated path, unchanged); every other session gets the pointer compositor-EMBEDDED at creation (KWin zkde pointer=2, Mutter cursor-mode=1, wlroots/hyprland portal CursorMode::Embedded — their pre-channel default; the portal pair also gains the Metadata arm for channel sessions, wired but untested on-glass). SessionPlan.cursor_blend narrows to cursor-forward sessions and rides into the direct-SDK NVENC open, which skips the Vulkan slot-blend bring-up entirely when off — embedded sessions ring on plain CUDA surfaces and pay zero cursor cost, per-session or per-frame. The keep-alive registry's reuse key grows the created pointer mode (new VirtualDisplay::hw_cursor getter): a kept embedded display has no cursor metadata for a channel session to forward, and a kept metadata display would leave a channel-less session with no pointer in its frames. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -142,13 +142,25 @@ pub trait VirtualDisplay: Send {
|
||||
/// the backend's default EDID. Default: no-op — only the Windows pf-vdisplay backend can mint
|
||||
/// per-monitor EDIDs today (the Linux compositors' virtual outputs take no EDID from us).
|
||||
fn set_client_hdr(&mut self, _hdr: Option<punktfunk_core::quic::HdrMeta>) {}
|
||||
/// Ask the backend for an out-of-band HARDWARE CURSOR on the created output (the M2c cursor
|
||||
/// channel): the compositor/OS stops compositing the pointer into captured frames and the
|
||||
/// capture layer surfaces shape/position separately. Carried on the backend instance; set
|
||||
/// once before [`create`](Self::create). Default: no-op — only the Windows pf-vdisplay
|
||||
/// backend (IddCx hardware cursor, driver proto v5) implements it; the Linux portal path
|
||||
/// gets the same split from `SPA_META_Cursor` without asking.
|
||||
/// Ask the backend for an OUT-OF-BAND cursor on the created output (the cursor channel):
|
||||
/// the compositor/OS stops compositing the pointer into captured frames and the capture
|
||||
/// layer surfaces shape/position separately. Carried on the backend instance; set once
|
||||
/// before [`create`](Self::create) (both session paths pass `cursor_forward`). Off = the
|
||||
/// compositor EMBEDS the pointer into frames — zero host-side cursor work, the pre-channel
|
||||
/// path — which is what every session without the negotiated cursor cap gets (Moonlight /
|
||||
/// GameStream / legacy clients / capture-mode starts), mirroring the Windows no-regression
|
||||
/// gate. Implementations: Windows pf-vdisplay (IddCx hardware cursor, driver proto v5);
|
||||
/// KWin (zkde `pointer` metadata vs embedded); Mutter (`cursor-mode` metadata vs embedded);
|
||||
/// wlroots/hyprland (portal `CursorMode`). Default: no-op (gamescope has no cursor either
|
||||
/// way — see the Phase C source).
|
||||
fn set_hw_cursor(&mut self, _on: bool) {}
|
||||
/// The out-of-band-cursor request currently set (see [`set_hw_cursor`](Self::set_hw_cursor)).
|
||||
/// The registry includes it in the keep-alive REUSE key: a kept embedded-pointer display can
|
||||
/// never serve a cursor-channel session (its stream has no cursor metadata to forward) nor
|
||||
/// vice versa (the pointer would be missing from frames).
|
||||
fn hw_cursor(&self) -> bool {
|
||||
false
|
||||
}
|
||||
/// The stable identity slot the backend resolved for the most recent [`create`](Self::create) —
|
||||
/// the per-client id the identity policy assigned (`Some`), or `None` for shared/anonymous. The
|
||||
/// registry reads it right after `create` to key the display's group **arrangement** (manual
|
||||
|
||||
Reference in New Issue
Block a user