feat(host/windows): native res, cursor, secure-desktop capture, windowless SYSTEM launch
apple / swift (push) Successful in 52s
ci / rust (push) Failing after 36s
ci / web (push) Successful in 31s
android / android (push) Successful in 1m52s
ci / docs-site (push) Successful in 29s
ci / bench (push) Successful in 1m39s
decky / build-publish (push) Successful in 11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
deb / build-publish (push) Successful in 3m19s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 5m15s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 4m57s
docker / deploy-docs (push) Successful in 17s

Live-validated Mac <-> RTX 4090 at the display's native 5120x1440@240:

- Resolution: set_active_mode enumerates the IDD's advertised modes and sets the
  requested resolution at the best supported refresh (keeps 5120x1440@240; no more
  silent fallback to the 1080p OS default when an exact mode is briefly unavailable).
- Bitrate auto-cap: NVENC init probes and steps the average bitrate down to the GPU's
  codec-level max so a high client bitrate connects (matches the Linux host; we do not
  split NVENC sessions).
- Mouse cursor: DXGI duplication excludes the HW cursor; capture the pointer
  shape/position (GetFramePointerShape) and GPU-composite it before NVENC. Color cursors
  alpha-blend; masked-color (the text I-beam) uses an INV_DEST_COLOR inversion blend so
  the caret inverts the screen and shows on any background (no black box); monochrome
  handled too.
- Secure desktop (lock / login / UAC): run as SYSTEM in the interactive session, follow
  the input desktop via SetThreadDesktop, and on the WinSta switch recreate the D3D11
  device and re-resolve the virtual output's GDI name from the stable SudoVDA target id
  (the name changes across the topology rebuild; the old failure hunted the stale
  \\.\DISPLAYn and dropped). ACCESS_LOST / INVALID_CALL / device-removed are recoverable,
  and a mid-stream resolution change is followed (capturer + NVENC re-init at the new
  size). isolate_displays detaches other monitors so Winlogon renders to the virtual
  output. One real session recovered 1012 desktop switches and completed cleanly.

Windows-only backends; Linux/macOS unaffected. Builds clean on x86_64-pc-windows-msvc.
Deployment (windowless SYSTEM launch via PsExec + hidden VBScript) documented in
docs/windows-host.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-15 15:46:34 +00:00
parent 1f0dc87658
commit f4b4a6c1e4
6 changed files with 1124 additions and 106 deletions
+36
View File
@@ -47,6 +47,42 @@ coexisting with a running Apollo (two concurrent NVENC sessions).
- **Frame pacing on static content** — DXGI duplication is change-driven, so a blank/idle virtual
display delivers only ~12 fps (181/177 frames over ~15 s); a rendering app drives the full rate.
### Live UX hardening (2026-06-15, validated Mac ↔ RTX 4090)
Driven by live testing with the native macOS client at the display's native **5120×1440@240**:
- **Native resolution, not 1080p.** `sudovda::set_active_mode` enumerates the modes the IDD actually
advertises (`EnumDisplaySettingsW`) and sets the requested **resolution** at the best supported
refresh — keeping 5120×1440@240, never silently collapsing to the 1280×720/1920×1080 OS default
when an exact mode is briefly unavailable.
- **Bitrate auto-cap.** NVENC `init_session` probes and steps the average bitrate down (×3/4 to a
floor) when the requested rate exceeds the GPU's codec-level max, so a high client bitrate connects
instead of failing (matches the Linux host; we do NOT split NVENC sessions).
- **Mouse cursor.** DXGI duplication excludes the hardware cursor; we read the pointer
position/shape from the frame info (`GetFramePointerShape`) and GPU-composite it onto the captured
texture before NVENC (a CPU read-back would stall the pipeline). Color cursors alpha-blend;
**masked-color** cursors (the text I-beam) use an `INV_DEST_COLOR` blend for true screen inversion,
so the caret is visible on any background (no black box). Monochrome handled too.
- **Secure desktop (lock / login / UAC).** The host runs as **SYSTEM in the interactive session**;
the capturer `SetThreadDesktop`s onto the current input desktop and, on the WinSta switch,
**recreates the D3D11 device** and **re-resolves the virtual output's GDI name from the stable
SudoVDA target id** (the name changes across the topology rebuild — the old failure was hunting the
stale `\\.\DISPLAYn` and dropping). `ACCESS_LOST` / `INVALID_CALL` / device-removed are all treated
as recoverable, and a mid-stream resolution change is followed (capturer + NVENC re-init at the new
size). Validated: logging in / locking through the stream stays connected (one real session
recovered 1012 desktop switches and completed cleanly). *Display isolation* (`isolate_displays`
detaches other monitors so Winlogon renders to the virtual output) covers the case where a physical
monitor is also attached.
### Running as SYSTEM, windowless (deployment)
To capture the secure desktop the host must run as **SYSTEM in the interactive Session 1** (a Session
0 service can't duplicate Session 1). Launch chain: a scheduled task (Interactive, Highest) →
`PsExec64 -s -i 1 -d wscript.exe launch.vbs``launch.vbs` runs `host-run.cmd` with a **hidden
window** (`WScript.Shell.Run …, 0`). This keeps the host off the captured desktop — no `cmd` windows
the user can see or accidentally close (which would kill the stream). `host-run.cmd` sets
`APPDATA=C:\Users\Public` (shared identity/pairing) + `PUNKTFUNK_ENCODER=nvenc` and runs `m3-host`.
### Real-GPU test box (RTX 4090, `ssh "Enrico Bühler"@192.168.1.174`)
Windows 11, RTX 4090 (driver 596.36) + AMD iGPU, SudoVDA + Apollo (sunshine) installed. SSH lands in