Commit Graph

3 Commits

Author SHA1 Message Date
enricobuehler 986402f731 fix(inject,zerocopy,capture): teardown deadlock, GL→CUDA copy race, cursor-meta OOB read
The three high-severity defects from the round-1 sweep of pf-inject /
pf-zerocopy / pf-capture (adjudicated against source — all 7 reported criticals
in these crates downgraded; these were the real highs).

- pf-inject steam_gadget: `SteamDeckGadget::drop` set `running=false` then joined
  the control thread, which spends steady state parked in a blocking, no-timeout
  `EVENT_FETCH` ioctl that only tests `running` at its loop top. The flag never
  reaches it, closing the fd can't wake an in-flight ioctl (the syscall holds a
  file reference, and the fd is shared via Arc by the very threads being joined),
  so the join hung — and it runs on the session input thread via
  `PadSlots::sweep`, driven by the client's `active_mask`, so a remote peer
  clearing its pad bit could freeze all session input. Now wakes the parked
  threads with SIGUSR1 (no-op, non-SA_RESTART handler → the ioctl returns EINTR
  and the loop exits), retried until each reports done and bounded (~1s).

- pf-zerocopy cuda: the GL→CUDA "sync point" was never established for the copy.
  `cuGraphicsMapResources`/`UnmapResources` were issued on the NULL stream, but
  the D2D copy runs on `copy_stream()`, a `CU_STREAM_NON_BLOCKING` stream exempt
  from implicit NULL-stream ordering — and the GL de-tile/CSC that produced the
  texture ends with only `glFlush` (no fence). So the copy could race ahead of
  the not-yet-retired GL draw: intermittent stale/torn frames under GPU load, on
  the default NVIDIA capture→encode path. Map, copy, and unmap now share
  `copy_stream()`, so map's device-side guarantee orders the GL work before the
  copy. Zero-copy preserved (no GPU→CPU→GPU roundtrip).

- pf-capture cursor meta: `update_cursor_meta` trusted three producer-written
  fields (bitmap_offset, pixel offset, stride) with no bound against the metadata
  region, driving OOB pointer arithmetic and an oversized `from_raw_parts` — an
  OOB read that SIGSEGVs inside the PipeWire `.process` callback (uncatchable by
  the surrounding `catch_unwind`). Switched to `spa_buffer_find_meta` to obtain
  the region's real `size` and validate every offset with checked arithmetic
  before each deref/slice, mirroring the fd-length guard the main frame path
  already applies.

Compile + existing tests green on Linux .21 (real RTX 5070 Ti): pf-inject 74/0,
pf-zerocopy 17/0, pf-capture 1/0. The gadget deadlock path only executes on a
SteamOS host with raw_gadget/dummy_hcd (not reproducible on the CachyOS box), so
that fix is reasoned + compile-verified, not runtime-exercised.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 22:53:15 +02:00
enricobuehler 5e1e64e50b perf(latency): T2.5b — NV12 compute CSC on the LINEAR/gamescope zero-copy path
apple / swift (push) Successful in 1m21s
apple / screenshots (push) Successful in 6m23s
ci / web (push) Successful in 54s
arch / build-publish (push) Successful in 10m52s
ci / docs-site (push) Successful in 1m7s
decky / build-publish (push) Successful in 35s
android / android (push) Successful in 13m2s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 16s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 16s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 11s
ci / bench (push) Successful in 6m8s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 7m56s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 9m44s
docker / deploy-docs (push) Successful in 24s
deb / build-publish (push) Successful in 11m52s
ci / rust (push) Successful in 27m4s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 20m26s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 20m20s
design/latency-reduction-2026-07.md T2.5's Linux half: the LINEAR dmabuf path
(gamescope's only offer) fed NVENC RGB, paying its internal RGB->YUV CSC on
the SM the game is saturating — the exact contention §5.A removed everywhere
else. The Vulkan bridge now carries a buffer-to-buffer RGB->NV12 compute
shader (rgb2nv12_buf.comp, BT.709 limited, coefficient-identical to
pf-encode's rgb2yuv.comp; whole-word writes so no 8-bit-storage feature is
needed): import dmabuf -> dispatch CSC into the exportable buffer -> CUDA
de-strides both planes into a pooled two-plane NV12 buffer. PUNKTFUNK_NV12
(default-on) now covers LINEAR; a CSC failure latches RGB for the stream
(mid-frame fallback, no dropped frame); 4:4:4 LINEAR sessions stay RGB (never
silently subsample). New ImportKind::LinearNv12 rides the existing worker IPC
(appended last per the wire-tag rule); cursor stays downstream (blend_nv12).

Validated: .21 clippy -D warnings (pf-zerocopy/pf-capture/host+nvenc) + 17
zero-copy tests. Owed: on-glass gamescope session (visual + dmon sm% check).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 20:14:20 +02:00
enricobuehler 85bc5b9a3f refactor(host/W6.2): extract the Linux zero-copy GPU plumbing into the pf-zerocopy leaf crate
linux/zerocopy/* (CUDA context/buffers + EGL/Vulkan dmabuf import + the isolated
import worker) and linux/dmabuf_fence.rs move wholesale into crates/pf-zerocopy,
so the coming pf-frame vocabulary crate (FramePayload::Cuda owns a DeviceBuffer)
and the pf-encode/pf-capture subsystem crates can reach the GPU plumbing without
the host orchestrator in between (plan §W6). Content stays Linux-only; the crate
compiles to an empty lib elsewhere, so dependents carry a plain dependency.

drm_fourcc deliberately does NOT move: it consumes the frame vocabulary
(PixelFormat), which sits ABOVE pf-zerocopy — it lives with capture for now and
moves into pf-frame next. cuda's ffi re-export bumps pub(crate)->pub (the raw
CUdeviceptr vocabulary is consumed across the crate boundary by the encode
backends). A crate::zerocopy shim module keeps every existing path valid until
capture/encode themselves move out.

Verified: Linux clippy -D warnings (pf-zerocopy --all-targets + host
nvenc,vulkan-encode,pyrowave --all-targets) + 17/17 pf-zerocopy tests + 321/321
host tests; Windows clippy nvenc,amf-qsv --all-targets Finished exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 09:41:15 +02:00