chore(pf-capture): make the crate verifiable — Windows CI lint + two denies (sweep Phase 0)

Gate for the rest of design/pf-capture-sweep.md: today half this crate is compiled by no CI job
at all, so the Windows-side findings can't even be type-checked.

0.1 (X1) — windows-host.yml lints `-p pf-capture --all-targets`. The host lint above it builds
pf-capture only as a DEPENDENCY, so its `#[cfg(test)]` modules were never compiled anywhere: the
5 StallWatch tests, the DXGI HDR self-tests and the cursor-conversion tables were dead code in
CI. The workflow's own comment already diagnosed this blind spot and fixed it for pf-encode;
pf-capture never got the same treatment. No features on this crate, so no feature juggling and
no extra dep tree.

0.2 (X2) — `#![deny(unsafe_op_in_unsafe_fn)]` beside the existing
`deny(clippy::undocumented_unsafe_blocks)`. The crate declares "every unsafe block carries a
SAFETY proof; enforce it" in ten file headers, but in edition 2021 that lint has nothing to fire
on inside an `unsafe fn` — so the hardest FFI in the crate was exempt from its own program: the
ring/slot construction, the fence signal, the blend scratch, and every D3D converter ctor/convert.
119 operations across 16 functions now carry a proof. `shared_object_sa` loses its `unsafe`
marker instead (it states no precondition — only its RESULT is a raw pointer, which is the
caller's business).

0.3 (X4) — drop the crate-wide `#![allow(dead_code)]`. Verified: zero warnings on either target
without it, so it was hiding nothing the lint can see (W16's dead items are `pub`/written-once,
so they need Phase 1.7's deletion instead).

No behaviour change: only lint attributes, `unsafe { }` scoping and comments.

Linux `cargo test -p pf-capture` 6/6, clippy --all-targets clean on both targets (Windows
verified by cross-checking x86_64-pc-windows-msvc locally).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-26 10:18:48 +02:00
co-authored by Claude Opus 5
parent bf9386ecb2
commit 6a2a153c0b
6 changed files with 749 additions and 628 deletions
@@ -140,13 +140,17 @@ impl Capturer for SyntheticNv12Capturer {
/// # Safety
/// Calls DXGI factory/adapter enumeration; returns owned COM objects or an error.
unsafe fn resolve_render_adapter() -> Result<IDXGIAdapter1> {
let factory: IDXGIFactory4 = CreateDXGIFactory1().context("CreateDXGIFactory1")?;
if let Some(luid) = pf_gpu::resolve_render_adapter_luid() {
if let Ok(a) = factory.EnumAdapterByLuid::<IDXGIAdapter1>(luid) {
return Ok(a);
// SAFETY: three `?`/`Ok`-checked DXGI enumeration calls over owned locals — the factory is
// created here and the adapters it returns own their own COM references. No raw pointers.
unsafe {
let factory: IDXGIFactory4 = CreateDXGIFactory1().context("CreateDXGIFactory1")?;
if let Some(luid) = pf_gpu::resolve_render_adapter_luid() {
if let Ok(a) = factory.EnumAdapterByLuid::<IDXGIAdapter1>(luid) {
return Ok(a);
}
}
factory.EnumAdapters1(0).context("EnumAdapters1(0)")
}
factory.EnumAdapters1(0).context("EnumAdapters1(0)")
}
/// Create an NV12 `Texture2D` with the given usage/CPU-access/bind flags.
@@ -177,8 +181,12 @@ unsafe fn create_nv12(
..Default::default()
};
let mut tex: Option<ID3D11Texture2D> = None;
device
.CreateTexture2D(&desc, None, Some(&mut tex))
.context("CreateTexture2D(NV12)")?;
// SAFETY: one `?`-checked `CreateTexture2D` on the live `device` borrow (per the contract
// above), with a fully-initialized stack descriptor and a live `Option` out-param.
unsafe {
device
.CreateTexture2D(&desc, None, Some(&mut tex))
.context("CreateTexture2D(NV12)")?;
}
tex.context("CreateTexture2D returned a null NV12 texture")
}