Files
punktfunk/docs/windows-host-goal1-plan.md
T

92 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Goal-1 (clean, layered host architecture) — staged execution plan
The design is in [`windows-host-rewrite.md`](windows-host-rewrite.md) §2.22.4. This file is the **ordered,
independently-shippable execution plan**, because the host is **live-validated** (GameStream + punktfunk/1,
NVENC + IDD-push on-glass) and Goal-1 rewires its session/config/dispatch flow — so every stage must
**preserve behavior**, compile + box-verify on its own, and be committed before the next starts. The plan's
own §14 makes the §1 preservation checklist a mandatory per-module assert contract; honour it.
## Why staged (not one big rewrite)
`main` is at parity and shipping. A monolithic rewrite would put the validated host in a broken
intermediate state for a long window and make a regression impossible to bisect. Each stage below is a
behaviour-preserving transform with its own verification, so a regression is caught at the stage that
introduced it.
## Stages (ordered; each = goal · files · risk · verify)
**Stage 1 — `HostConfig` foundation. ✅ DONE (this commit).**
`config.rs`: typed `HostConfig` parsed ONCE from env (`idd_push`/`encoder_pref`/`no_helper`/`force_helper`).
Migrated the two highest-churn dispatch reads onto it (`encode::windows_resolved_backend`,
`punktfunk1::should_use_helper`). Risk: low (env constant at runtime → identical behaviour). Verify: box
`cargo check --features nvenc`.
**Stage 2 — finish `HostConfig` + resolve-once. ✅ DONE (this commit).**
Migrated **31** genuinely-constant operator/dispatch sites onto `HostConfig`: `idd_push` ×7 (the
capture/topology disagreement knob), `no_wgc`, `capture_backend`, `render_adapter`, `encoder_pref` (Linux),
the Windows vdisplay-backend select, plus the plan-named `secure_dda`/`idd_depth`/`zerocopy`/`ten_bit` and the
multi-site `perf` ×4 / `compositor` ×5 / `video_source` ×3 / `gamepad`. Each `HostConfig` field's parser is
**byte-identical** to the read it replaced, so `old == new` by construction (the §1 "flipped bool" guard).
**Scope correction (the plan's "~64 sites / Linux XDG+compositor / grep→0" was unsafe as written):** two
classes of `env::var` read are deliberately **kept live** and documented in `config.rs`:
- **Runtime-mutated session vars.** On Linux, `vdisplay::apply_session_env` *rewrites the process env on
every connect* (the Bazzite Gaming↔Desktop follow): `WAYLAND_DISPLAY`, `XDG_CURRENT_DESKTOP`,
`XDG_RUNTIME_DIR`, `DBUS_SESSION_BUS_ADDRESS`, and the derived `PUNKTFUNK_INPUT_BACKEND`,
`PUNKTFUNK_GAMESCOPE_SESSION/NODE`, `PUNKTFUNK_KWIN/MUTTER_VIRTUAL_PRIMARY`, `PUNKTFUNK_FORCE_SHM`.
Parse-once would freeze them at startup → silent session-following regression. They are NOT constant.
- **Single-use local tuning** (no resolve-once benefit, call-site-local default/clamp, and `FEC_PCT` even has
*two different* semantics): `FEC_PCT`, `VIDEO_DROP`, `VBV_FRAMES`, `SPLIT_ENCODE`, `PACE_BURST_KB`, the
`capture/dxgi.rs` timing knobs, the `*_LIVE`/test gates, plus path/dynamic reads (config-dir, `PATH`
search, env-forward-to-child). `PUNKTFUNK_ZEROCOPY` is split on purpose: Windows presence-semantics moved
to the field; Linux keeps its own truthy parser.
Risk: medium (semantics-preservation). Verify: Linux `cargo check`/`clippy`/`fmt` green (the Windows-only
edits are 1:1 substitutions, compile-verified on the box as part of Stage 3's build).
**Stage 3 — `SessionPlan` (the single biggest clarity lever, plan §2.4). ✅ IMPLEMENTED (this commit; on-glass pending).**
New `src/session_plan.rs`: a `Copy` `SessionPlan { capture, topology, encoder, bit_depth, hdr }` resolved
**once** from `HostConfig` (+ the negotiated `bit_depth`) in `virtual_stream`, logged, and threaded through
`build_pipeline_with_retry`/`build_pipeline`. The three dispatch points now read it:
- **capture** — `capture::capture_virtual_output` takes a `CaptureBackend` IN (was re-deriving from
`config().idd_push`/`capture_backend`/`no_wgc`); `CaptureBackend::resolve()` is the one resolver (also
used by the GameStream + spike call sites).
- **topology** — `virtual_stream` reads `plan.topology` (`should_use_helper` deleted; its logic is
`session_plan::resolve_topology`, verbatim). The IDD-preempt guard reads `plan.capture` too.
- **encoder** — recorded as `EncoderBackend` from `encode::windows_resolved_backend` (config-backed +
GPU-vendor cached since stage 2, already a single source). Threading `encoder`/`input_format` into the
encoder + capturer opens (which removes the `dxgi.rs` back-reference) is **stage 5**.
Every decision is provably equivalent to the pre-stage-3 scattered reads (same `config()` + cached probes),
so it is behavior-preserving. Risk: medium-high (rewires the deployed decision). Verify:
- **Box build ✅** — `cargo check -p punktfunk-host --features nvenc` (the deployed config: NVENC SDK +
`cudarc` + `encode/nvenc.rs`) is **clean, zero warnings**, on the RTX box (`192.168.1.173`), in an
isolated worktree. This also covers stage 2's Windows-only edits (their first real Windows compile).
- **On-glass** (NVENC + IDD-push + a mode switch) — **pending**: needs the host+driver+client deployed on
the box, which currently holds active driver WIP; coordinate before swapping the running service.
**Stage 4 — `SessionContext` + `SessionFactory`/`Session`.**
Bundle the 1213-arg `#[allow(too_many_arguments)]` signatures into `SessionContext`; `SessionFactory.build()`
owns the RAII chain `vdm.lease(mode) → open_capturer(vout, fmt) → open_encoder(plan) → spawn pipeline`, with
`Session::drop` the ONLY teardown path. Risk: high (teardown ordering — the §1 RAII asserts are mandatory).
Verify: box build + on-glass (connect/disconnect/reconnect, no leaked monitors/threads).
**Stage 5 — seam-trait tightenings (plan §2.3).**
`Capturer::open_capturer(vout, want: OutputFormat)` takes the format IN (kills the
`capture → encode::windows_resolved_backend()` back-reference recomputed in `dxgi.rs`); HDR/release become
`VirtualLease` methods (session glue names no concrete backend, contains no `unsafe`); optional encoder
features move to `EncoderCaps`. Risk: medium. Verify: box build + on-glass.
**Stage 6 — `src/windows/` tree (cfg-sprawl confinement, plan §2.2).**
Move the Windows backends under `src/windows/` + `capture/windows/`, `encode/windows/`, `inject/windows/`,
`audio/windows/`, `vdisplay/windows.rs` behind one `#[cfg(windows)] mod windows;` seam. Pure file move +
mod/use-path updates — behaviour-identical. Risk: low-but-huge (dozens of files; compile-verify catches all).
Do LAST so the earlier semantic stages don't fight path churn. Verify: Linux + box build.
## Guardrails (mandatory, plan §14)
- Each stage is its own commit; box-verify before moving on.
- Stages 35 touch the deployed path → **on-glass re-test** (NVENC + IDD-push, a mode switch, a
connect/disconnect cycle) before the next stage.
- Preserve every `PUNKTFUNK_*` var's exact semantics; when in doubt, assert old==new at the call site.