ARM64 Windows host (Snapdragon X) — aarch64-pc-windows-msvc #298

Open
opened 2026-08-18 13:21:19 +00:00 by enricobuehler · 0 comments
Owner

Ship the Windows host natively on aarch64-pc-windows-msvc for Snapdragon X (X Elite / X Plus).

Design: design/media-foundation-encoder.md §5–§7 — punktfunk-planning PR #16 (branch docs/media-foundation-encoder), written against origin/main 9c133350; every file:line below re-verified there. Encoder half: #297.

Verdict: viable, and the encoder is the smaller half. The genuine critical path is the startup code-patch, the vdisplay driver, bun, and the update feed. aarch64-pc-windows-msvc is Tier 1; the host source is arch-clean (exactly one cfg(target_arch) site in the whole Windows host stack, and it is already ARM64-aware — wasapi_mic.rs:324-328). Sunshine ships an ARM64 host; Apollo and Parsec do not.

The recorded stance — "x64-only by design … no IddCx path on ARM64" (windows-build-and-packaging.md:15-17, packaging/windows/README.md:21-27) — rests on two premises that are stale: IddCx does exist on ARM64 (the MS sample ships an ARM64 config; third-party IDDs ship ARM64), and "the driver builds x64-only" describes our own .cargo/config.toml, not the platform. The premise that survives — no vendor encoder backend for Adreno — is exactly what #297 removes. Both docs must be updated when this lands.

P2 — the build leg (~1 week, no device needed)

  • B2 🛑 the first-boot crash. pf-capture/src/windows/dxgi.rs:104-190 install_gpu_pref_hook writes x86-64 opcodes (48 B8 … FF E0, mov rax,imm64; jmp rax) into win32u.dll!NtGdiDdDDIGetCachedHybridQueryValue. It is not cfg-gated and runs from punktfunk-host/src/main.rs:376 for every non-CLI subcommand — so it compiles clean on ARM64 and then corrupts a live code page. Fix: #[cfg(target_arch = "x86_64")] (its purpose, hybrid dGPU/iGPU reparenting, is moot on a single-GPU SoC). Do this first.
  • B3 the vdisplay driver. Windows capture is IDD direct-push only (pf-capture/src/lib.rs:567-568; DDA and the WGC relay are gone) ⇒ without an ARM64 pf_vdisplay that installs, no frame is ever captured. Pinned in four places: [build] target = "x86_64-pc-windows-msvc" in packaging/windows/drivers/.cargo/config.toml (the +crt-static trick there is load-bearing — add an [target.aarch64…] block, don't delete), const ARCH = "x64" in pf-vdisplay/build.rs:16 and wdk-probe/build.rs:17, stampinf -a amd64 / inf2cat /os:10_X64 in build-pf-vdisplay.ps1:152-153 + build-gamepad-drivers.ps1, and the output paths. Mechanical: the INX files are already NT$ARCH$ and the vendored wdk-build makefile already carries the aarch64 → arm64 / Server10_arm64 mapping. Signing is R4 below.
  • B4 bun has no Windows-ARM64 build — and it is the only runtime for both the web console and the plugin runner (windows-host.yml:293 pulls bun-windows-x64.zip). Decision, not code: accept x64 bun under Prism (background Nitro server, likely fine) or move the console runtime.
  • B5 the update feed has no arch axis. Single windows_host:{url,…} (publish-update-manifest.sh:107-110, pf-update-check/src/manifest.rs:63), unsuffixed latest/punktfunk-host-setup.exe (windows-host.yml:459), winget Architecture: x64 single entry. Without this an ARM64 box is handed the x64 installer. Schema bump + arch selection in update/windows.rs + _x64/_arm64 alias suffixes (the client already does this).
  • B6 CI. windows-host.yml:106,168,173 has no matrix and no --target; there is no ARM64 runner. Cross-build off the x64 runner — the client's ARM64 leg proves the toolchain is provisioned — build + clippy only; pf-capture/pf-vdisplay tests stay x64 until a Snapdragon runner exists.
  • C3 feature pruning. No nvenc (nvidia-video-codec-sdk link-imports the driver import lib — won't link), no qsv (libvpl-sys/build.rs guards target_os only and would CMake the Intel dispatcher for aarch64 — add a target_arch guard), no amf-qsv. punktfunk-host default is ["pyrowave","gamestream"]--no-default-features --features gamestream[,pyrowave] pending R2.
  • C4 one-liners. Inno ArchitecturesAllowed=x64 (punktfunk-host.iss:99-100), winget arch, the nefcon \x64\ regex, pf-vkhdr-layer built without --target (pack-host-installer.ps1:308-320).
  • Inno ARM64 installer, docs-site arch note, and the two stale docs above.

Already paid for: aws-lc-sys, libopus (CMake) and openh264-sys2 already cross-compile to aarch64-pc-windows-msvc via the client's ARM64 leg — that removes most of the C-build risk in one stroke. The tray (pure Win32), service install, WASAPI/IPolicyConfig audio minting and pf-inject (SendInput + our own UMDF HID drivers — no ViGEmBus anywhere in the tree) are arch-neutral. windows = "0.62" single-versioned, every requested feature has aarch64 metadata.

P3 — on-glass (needs a device)

The project owns no Windows-on-ARM box. The Snapdragon Dev Kit was cancelled (2024-10); a used Surface Laptop 7 / Dell XPS 13 9345 / Lenovo Yoga Slim 7x (X1E-78/80) is the realistic rig — an X Plus answers the floor, an X Elite the ceiling. Azure WoA VMs have no Adreno (software MFT only) — good for build/CI, useless for the encoder questions.

The encoder-side unknowns (ForceKeyFrame, LTR, mid-stream bitrate re-set, latency, HEVC/AV1 usability, SPS/PPS repeat, real max res/fps) are Q1–Q7 in the design doc §6 and belong to #297. Host-side:

  • R1 audio. Does Steam ship Steam\drivers\Windows10\arm64\SteamStreaming{Speakers,Microphone}.inf? Post-VB-CABLE those are the only audio substrate — the resolver and installer already look in arm64\. If not: no audio on WoA, and that is a separate design.
  • R2 Does PyroWave's Vulkan compute path run on Adreno X1 (subgroup ops, 16-bit storage, D3D fence import — pyrowave.rs:388-390)? If not, drop pyrowave from the ARM64 build and MF is the only rung.
  • R3 Does the ARM64 IddCx 1.10 driver start on 22H2+? Expected yes.
  • R4 🛑 signing. Our drivers are self-signed with the .cer imported as a machine root (packaging/windows/README.md:160-176); field reports say self/test-signed drivers accepted on x64 SKUs are rejected on ARM64 SKUs. Attestation signing does support ARM64 — the README already calls attestation "the real fix"; this becomes the forcing function.
  • R5 WASAPI endpoint loopback had one Snapdragon report of GetNextPacketSize() == 0; fallback is process-loopback via ActivateAudioInterfaceAsync.
  • R6 (informational, 5 min) Does x64 ffmpeg -c:v h264_mf -hw_encoding true find the QCOM MFT under Prism?

Then: a VENDOR_QUALCOMM caps table per SoC, request_keyframe fallback if Q1 fails, RFI only if Q2 passes.

P4 — release

Canary channel for _arm64, docs, announce. Q1's answer decides whether the ARM64 host is announced with "loss recovery: IDR" or with a finite-GOP caveat.

Rejected alternatives (see design §8)

PyroWave-only (wired-LAN, opt-in, 100–400 Mbps, no GameStream client can decode it) · openh264-only (NEON .S files are skipped on aarch64-pc-windows-msvcopenh264-sys2/build.rs:279-303 — a NEON-less C++ encoder on laptop cores) · FFmpeg h264_mf via amf-qsv (needs a winarm64 FFmpeg tree we'd have to start shipping again) · D3D12 Video Encode (not exposed by Qualcomm's driver) · x64 host under Prism (carries B2 into a hybrid system DLL).

Ship the Windows host natively on `aarch64-pc-windows-msvc` for Snapdragon X (X Elite / X Plus). Design: `design/media-foundation-encoder.md` §5–§7 — **punktfunk-planning PR #16** (branch `docs/media-foundation-encoder`), written against `origin/main` `9c133350`; every file:line below re-verified there. Encoder half: #297. **Verdict: viable, and the encoder is the *smaller* half.** The genuine critical path is the startup code-patch, the vdisplay driver, bun, and the update feed. `aarch64-pc-windows-msvc` is Tier 1; the host source is arch-clean (exactly **one** `cfg(target_arch)` site in the whole Windows host stack, and it is already ARM64-aware — `wasapi_mic.rs:324-328`). Sunshine ships an ARM64 host; Apollo and Parsec do not. The recorded stance — "x64-only by design … no IddCx path on ARM64" (`windows-build-and-packaging.md:15-17`, `packaging/windows/README.md:21-27`) — rests on two premises that are stale: **IddCx does exist on ARM64** (the MS sample ships an ARM64 config; third-party IDDs ship ARM64), and "the driver builds x64-only" describes our own `.cargo/config.toml`, not the platform. The premise that survives — no vendor encoder backend for Adreno — is exactly what #297 removes. **Both docs must be updated when this lands.** ## P2 — the build leg (~1 week, no device needed) - [ ] **B2 🛑 the first-boot crash.** `pf-capture/src/windows/dxgi.rs:104-190` `install_gpu_pref_hook` writes **x86-64 opcodes** (`48 B8 … FF E0`, `mov rax,imm64; jmp rax`) into `win32u.dll!NtGdiDdDDIGetCachedHybridQueryValue`. It is **not** `cfg`-gated and runs from `punktfunk-host/src/main.rs:376` for every non-CLI subcommand — so it compiles clean on ARM64 and then corrupts a live code page. Fix: `#[cfg(target_arch = "x86_64")]` (its purpose, hybrid dGPU/iGPU reparenting, is moot on a single-GPU SoC). **Do this first.** - [ ] **B3 the vdisplay driver.** Windows capture is **IDD direct-push only** (`pf-capture/src/lib.rs:567-568`; DDA and the WGC relay are gone) ⇒ without an ARM64 `pf_vdisplay` that installs, **no frame is ever captured**. Pinned in four places: `[build] target = "x86_64-pc-windows-msvc"` in `packaging/windows/drivers/.cargo/config.toml` (the `+crt-static` trick there is load-bearing — **add** an `[target.aarch64…]` block, don't delete), `const ARCH = "x64"` in `pf-vdisplay/build.rs:16` and `wdk-probe/build.rs:17`, `stampinf -a amd64` / `inf2cat /os:10_X64` in `build-pf-vdisplay.ps1:152-153` + `build-gamepad-drivers.ps1`, and the output paths. Mechanical: the INX files are already `NT$ARCH$` and the vendored `wdk-build` makefile already carries the `aarch64 → arm64 / Server10_arm64` mapping. Signing is R4 below. - [ ] **B4 bun has no Windows-ARM64 build** — and it is the only runtime for both the web console and the plugin runner (`windows-host.yml:293` pulls `bun-windows-x64.zip`). Decision, not code: accept x64 bun under Prism (background Nitro server, likely fine) or move the console runtime. - [ ] **B5 the update feed has no arch axis.** Single `windows_host:{url,…}` (`publish-update-manifest.sh:107-110`, `pf-update-check/src/manifest.rs:63`), unsuffixed `latest/punktfunk-host-setup.exe` (`windows-host.yml:459`), winget `Architecture: x64` single entry. Without this an ARM64 box is handed the x64 installer. Schema bump + arch selection in `update/windows.rs` + `_x64`/`_arm64` alias suffixes (the client already does this). - [ ] **B6 CI.** `windows-host.yml:106,168,173` has no matrix and no `--target`; there is no ARM64 runner. Cross-build off the x64 runner — the client's ARM64 leg proves the toolchain is provisioned — build + clippy only; `pf-capture`/`pf-vdisplay` tests stay x64 until a Snapdragon runner exists. - [ ] **C3 feature pruning.** No `nvenc` (`nvidia-video-codec-sdk` link-imports the driver import lib — won't link), no `qsv` (`libvpl-sys/build.rs` guards `target_os` only and would CMake the Intel dispatcher for aarch64 — **add a `target_arch` guard**), no `amf-qsv`. `punktfunk-host` default is `["pyrowave","gamestream"]` ⇒ `--no-default-features --features gamestream[,pyrowave]` pending R2. - [ ] **C4 one-liners.** Inno `ArchitecturesAllowed=x64` (`punktfunk-host.iss:99-100`), winget arch, the nefcon `\x64\` regex, `pf-vkhdr-layer` built without `--target` (`pack-host-installer.ps1:308-320`). - [ ] Inno ARM64 installer, docs-site arch note, and the two stale docs above. **Already paid for:** `aws-lc-sys`, libopus (CMake) and `openh264-sys2` already cross-compile to `aarch64-pc-windows-msvc` via the client's ARM64 leg — that removes most of the C-build risk in one stroke. The tray (pure Win32), service install, WASAPI/IPolicyConfig audio minting and `pf-inject` (`SendInput` + our own UMDF HID drivers — **no ViGEmBus anywhere in the tree**) are arch-neutral. `windows = "0.62"` single-versioned, every requested feature has aarch64 metadata. ## P3 — on-glass (needs a device) **The project owns no Windows-on-ARM box.** The Snapdragon Dev Kit was cancelled (2024-10); a used Surface Laptop 7 / Dell XPS 13 9345 / Lenovo Yoga Slim 7x (X1E-78/80) is the realistic rig — an X Plus answers the floor, an X Elite the ceiling. Azure WoA VMs have **no Adreno** (software MFT only) — good for build/CI, useless for the encoder questions. The encoder-side unknowns (ForceKeyFrame, LTR, mid-stream bitrate re-set, latency, HEVC/AV1 usability, SPS/PPS repeat, real max res/fps) are Q1–Q7 in the design doc §6 and belong to #297. Host-side: - [ ] **R1 audio.** Does Steam ship `Steam\drivers\Windows10\arm64\SteamStreaming{Speakers,Microphone}.inf`? Post-VB-CABLE those are the **only** audio substrate — the resolver and installer already look in `arm64\`. If not: **no audio on WoA**, and that is a separate design. - [ ] **R2** Does PyroWave's Vulkan compute path run on Adreno X1 (subgroup ops, 16-bit storage, D3D fence import — `pyrowave.rs:388-390`)? If not, drop `pyrowave` from the ARM64 build and MF is the only rung. - [ ] **R3** Does the ARM64 IddCx 1.10 driver start on 22H2+? Expected yes. - [ ] **R4 🛑 signing.** Our drivers are self-signed with the `.cer` imported as a machine root (`packaging/windows/README.md:160-176`); field reports say self/test-signed drivers accepted on x64 SKUs are **rejected on ARM64 SKUs**. Attestation signing does support ARM64 — the README already calls attestation "the real fix"; this becomes the forcing function. - [ ] **R5** WASAPI endpoint loopback had one Snapdragon report of `GetNextPacketSize() == 0`; fallback is process-loopback via `ActivateAudioInterfaceAsync`. - [ ] **R6** (informational, 5 min) Does x64 `ffmpeg -c:v h264_mf -hw_encoding true` find the QCOM MFT under Prism? Then: a `VENDOR_QUALCOMM` caps table per SoC, `request_keyframe` fallback if Q1 fails, RFI only if Q2 passes. ## P4 — release Canary channel for `_arm64`, docs, announce. Q1's answer decides whether the ARM64 host is announced with "loss recovery: IDR" or with a finite-GOP caveat. ## Rejected alternatives (see design §8) PyroWave-only (wired-LAN, opt-in, 100–400 Mbps, no GameStream client can decode it) · openh264-only (NEON `.S` files are skipped on `aarch64-pc-windows-msvc` — `openh264-sys2/build.rs:279-303` — a NEON-less C++ encoder on laptop cores) · FFmpeg `h264_mf` via `amf-qsv` (needs a `winarm64` FFmpeg tree we'd have to start shipping again) · D3D12 Video Encode (not exposed by Qualcomm's driver) · x64 host under Prism (carries B2 into a hybrid system DLL).
enricobuehler added this to the Roadmap project 2026-08-18 13:24:33 +00:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#298