fix(packaging/windows): Windows 11 22H2 floor + tray install task + stale console-port fixes

The OS floor is now enforced at install time (MinVersion=10.0.22621 with an
explanatory [Messages] override): pf-vdisplay is built against IddCx 1.10, and
on Windows 10 (incl. LTSC) / Win11 21H2 the device fails start with Code 10
STATUS_DEVICE_POWER_FAILURE (field-reported). Docs (site requirements/install/
windows-host pages + README) state the floor; new docs-site Security page.

Installer also gains the trayicon task (punktfunk-tray.exe file + HKLM Run key,
post-install launch as the signed-in user, upgrade taskkill + uninstall
--quit/taskkill choreography before file deletion), and the wizard/cleanup
text/port sweeps move off the stale :3000 web-console references to :47992
(cleanups sweep both for upgrades from old installs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 12:09:52 +00:00
parent 8005b11faf
commit 2c937855b3
18 changed files with 335 additions and 51 deletions
+14 -3
View File
@@ -45,7 +45,10 @@ interactive session for secure-desktop capture (why MSIX is unusable - see
| `packaging/windows/drivers/pf-dualsense/` `pf-xusb/` | `build-gamepad-drivers.ps1` (sign the workspace build) | `pf_{dualsense,xusb}.{dll,inf,cat}` + shared `.cer` |
| `packaging/windows/pf-vkhdr-layer/` | `pack-host-installer.ps1` (`cargo build --release`) | `pf_vkhdr_layer.dll` + `.json` |
| `web/` | `scripts/windows/build-web.ps1` (`bun run build`) | self-contained `.output` |
| `packaging/windows/nvenc/nvenc.def` | `gen-nvenc-importlib.ps1` (llvm-dlltool) | `nvencodeapi.lib` (link import, no GPU/SDK) |
(NVENC needs no build artifact: its entry points are resolved at runtime from the driver's
`nvEncodeAPI64.dll` — a link-time import would prevent the all-vendor exe from starting on
AMD/Intel-only machines.)
## 3. The driver workspace - `packaging/windows/drivers/`
@@ -118,8 +121,9 @@ needs, on the runner:
to the runner default). *History:* LLVM 21.1.2 was briefly pinned (`C:\llvm-21`) to dodge a
bindgen-0.71 layout-test overflow on clang 22; the 0.72 bump retired that pin, so there's now one
toolchain for both driver builds (the pack and `windows-drivers.yml`).
- NVENC import lib synthesised from a 2-export `.def` via `llvm-dlltool` (`gen-nvenc-importlib.ps1`) -
no GPU or NVIDIA SDK at build time.
- NVENC needs nothing at build time: the entry points are runtime-loaded from the driver's
`nvEncodeAPI64.dll` (`encode/windows/nvenc.rs` `load_api`). A link-time import would stop the
all-vendor exe from even starting on AMD/Intel-only machines.
- `FFMPEG_DIR` (the BtbN gpl-shared x64 tree) for the AMD/Intel AMF/QSV link; NASM + CMake +
`CMAKE_POLICY_VERSION_MINIMUM=3.5` for the CMake-from-source deps (aws-lc, opus).
- **Gotcha:** `CARGO_HOME` must be an ASCII path (a non-ASCII username breaks SDL3's MSVC precompiled
@@ -143,6 +147,13 @@ tasks** (all default-checked): install the pf-vdisplay driver, install the gamep
HDR Vulkan layer, start the service. Silent install: `/VERYSILENT` (omit a task with
`/MERGETASKS="!installdriver"`).
**OS floor: Windows 11 22H2 (build 22621)**`MinVersion=10.0.22621`, with a `[Messages]
WinVersionTooLowError` override naming the requirement. pf-vdisplay is built against **IddCx 1.10**
(the 1.10 `IddCxStub`, HDR `*2` DDIs, FP16 caps; no runtime `IddCxGetVersion` downgrade), which first
shipped in Windows 11 22H2 — on Windows 10 (incl. LTSC) / Windows 11 21H2 the driver package installs
but the device fails start with Code 10 `STATUS_DEVICE_POWER_FAILURE` (field-reported on Windows 10
LTSC, 2026-07). The installer gate turns that late failure into an upfront message.
Install-time work runs from `punktfunk-host.exe` subcommands, **not** locale-parsed PowerShell *files* -
the `[Run]` section calls `driver install [--gamepad] --dir <stage>` and `web setup --app-dir <app>
[--password-file <f>]` (`crates/punktfunk-host/src/windows/install.rs`). This is the ANSI-codepage
+23 -13
View File
@@ -82,12 +82,18 @@ query.
**IDD-push is the universal primary path.** Capture comes straight from the driver's shared keyed-mutex
texture ring (`capture/windows/idd_push.rs`) — no Desktop Duplication, no `win32u` reparenting hook. The
host creates the ring; the driver opens it (permissive `D:(A;;GA;;;WD)` SDDL). The generation-tagged
`latest = gen<<40 | seq<<8 | slot` stale-ring reject kills the HDR-flip garbage frame; a host-owned
3-slot `OUT_RING` rotated per frame is the texture-ownership contract that enables `pipeline_depth=2`
(convert/copy on the 3D engine overlapping NVENC on the ASIC). It captures the **secure desktop**
(Winlogon/UAC/lock) directly (validated 2026-06-25), so there is no separate secure capturer in the
primary path.
host creates the ring as a **sealed channel** (proto v2, `design/idd-push-security.md`): the header,
frame-ready event, and ring textures are **unnamed** (nothing to enumerate, open by name, or squat), and
the host `DuplicateHandle`s them into the driver's WUDFHost and delivers the handle *values* over the
SYSTEM+admins-only control device (`IOCTL_SET_FRAME_CHANNEL`), so only the two endpoint processes can
ever reach a frame — DDA's isolation property in user mode. (The objects keep a `D:(A;;GA;;;SY)(A;;GA;;;LS)`
DACL as defense-in-depth; it is no longer the isolation boundary. This supersedes the earlier named-ring
scheme, which was world-openable `Global\pfvd-*` (`D:(A;;GA;;;WD)`) then SY+LS-scoped.) The
generation-tagged `latest = gen<<40 | seq<<8 | slot` stale-ring reject kills the HDR-flip garbage frame;
a host-owned 3-slot `OUT_RING` rotated per frame is the texture-ownership contract that enables
`pipeline_depth=2` (convert/copy on the 3D engine overlapping NVENC on the ASIC). It captures the
**secure desktop** (Winlogon/UAC/lock) directly (validated 2026-06-25), so there is no separate secure
capturer in the primary path.
- **Open-time fallback:** `IddPushCapturer::open` waits a bounded ~4 s for a *first frame* (not just
`DRV_STATUS_OPENED`); on attach failure it returns the keepalive back so `capture.rs` opens **DDA** on
@@ -120,10 +126,12 @@ loss-recovery by query (only Windows direct-NVENC overrides it; the GameStream l
### 2.5 Host↔driver ABI & the `pf-vdisplay` driver
`pf-driver-proto` is one `no_std` crate in both build graphs. It owns the **frame plane** (`FrameToken`
+ `Global\pfvd-*` names), the **control plane** (a fresh interface GUID — *not* SudoVDA's `e5bcc234`;
contiguous `0x900` IOCTL ops; a `GET_INFO` version handshake the host **asserts** + bails on mismatch),
and the **gamepad SHM** (`XusbShm`/`PadShm` incl. `device_type`). `bytemuck`-`Pod` + `size_of` **and**
`offset_of!` asserts make ABI drift a **compile error**.
+ `SharedHeader`; since proto v2 the frame objects are **unnamed** — no `Global\pfvd-*` names — and are
delivered by handle duplication over `IOCTL_SET_FRAME_CHANNEL`, the *sealed channel*:
`design/idd-push-security.md`), the **control plane** (a fresh interface GUID — *not* SudoVDA's
`e5bcc234`; contiguous `0x900` IOCTL ops; a `GET_INFO` version handshake the host **asserts** + bails on
mismatch), and the **gamepad SHM** (`XusbShm`/`PadShm` incl. `device_type`). `bytemuck`-`Pod` +
`size_of` **and** `offset_of!` asserts make ABI drift a **compile error**.
The driver (`packaging/windows/drivers/pf-vdisplay/src/`) is an all-Rust UMDF IddCx driver on
`windows-drivers-rs` + the `iddcx` `wdk-sys` subset; the STEP 08 build is the checklist in §6.3, its
@@ -200,8 +208,10 @@ These are expensive empirical wins; keep them intact when touching the code:
the hot-loop `KeyedMutexGuard`, and the driver's `pod_init!`; all box-validated, clean `sc stop` in
~1 s). The driver already has the deny. Revisit D1-host as a final discipline pass (staged per-module)
if desired.
5. **M6 scaffolding cleanup** delete the bring-up diagnostics (`spawn_observer`/`DebugBlock` in
`idd_push.rs`) and, once full parity is proven on glass, the host monoliths.
5. **M6 scaffolding cleanup** — the bring-up diagnostics (`spawn_observer`/`DebugBlock` in
`idd_push.rs`) were deleted with the sealed-channel change (they were the last fixed-name
`Global\` objects on the frame path); once full parity is proven on glass, the host monoliths
remain.
**Explicitly NOT doing (stability decision): E1 — driver `DeviceContext` ownership + per-`IDDCX_MONITOR`
`EvtCleanupCallback`.** The current process-global design is *sound*: IddCx DDIs receive only an
@@ -260,7 +270,7 @@ Local pre-push checks (this Linux box can't compile the Windows paths):
cargo test -p pf-driver-proto # the ABI crate (cross-platform)
cargo check -p punktfunk-host # Linux paths; win_* mods are #[cfg(windows)]
cargo clippy -p punktfunk-host --all-targets -- -D warnings
# Windows host clippy (on the box): PUNKTFUNK_NVENC_LIB_DIR=C:\t\nvenc;
# Windows host clippy (on the box; NVENC needs no import lib — runtime-loaded):
# cargo clippy -p punktfunk-host --features nvenc --target x86_64-pc-windows-msvc -- -D warnings
# Driver build (on the box): cd packaging/windows/drivers; Version_Number=10.0.26100.0;
# LIBCLANG_PATH='C:\Program Files\LLVM\bin'; cargo build