forked from unom/punktfunk
Six crates were still unguarded, and all six are OURS — none vendored: pf-console-ui, pf-gpu, punktfunk-tray, clients/windows, tools/display-disturb, wdk-probe. Two of them ship (the tray and the Windows client), so "small" was about item count, not exposure. Five are closed here. Only 17 of their 75 unsafe items actually lacked a proof — pf-gpu, punktfunk-tray and display-disturb were already fully documented and needed nothing but the deny, which is the good case: the convention was being followed, just not enforced. The 17 that were missing are the usual Win32/COM shapes, and two were worth stating properly. `clients/windows`'s `GetCurrentPackageFullName` is called with `len = 0` and no buffer — that is the documented identity PROBE, which writes nothing, and reading it as a normal query would be a mistake. `pf-console-ui`'s two `destroy_image_view` calls are the load-bearing ones: the comment above one already argued that in-flight sampling of that slot ended two presents ago (the ring alternates and the presenter waits its fence before each record), which is exactly the kind of reasoning a `// SAFETY:` should carry and it was sitting there unlabelled. Also fixes a real Windows-only clippy error this uncovered: `pf-gpu` had a `#[cfg(target_os = "windows")]` fn AFTER its `mod tests`, tripping `items_after_test_module`. It never fired on Linux (the item does not exist there) and no CI job clippies pf-gpu on Windows, so it sat unseen. Moved above the test module. Remaining: `wdk-probe` (26 items) alone, and only because it needs the WDK to build — .47 cannot, so nothing here can verify a deny on it. Verified: Linux .21 fmt + both CI clippy steps rc=0; Windows .47 the four Windows-relevant crates at `-D warnings` rc=0.
89 lines
3.9 KiB
Rust
89 lines
3.9 KiB
Rust
//! DXGI adapter enumeration for the Settings "GPU" picker.
|
|
//!
|
|
//! Streaming (decode + present) runs in the spawned `punktfunk-session` binary; the shell only
|
|
//! needs the list of real (hardware) adapters to offer on a multi-GPU box (a hybrid laptop or an
|
|
//! eGPU). The picked adapter description is persisted (`crate::trust::Settings::adapter`) and read
|
|
//! by the session child at connect (`PUNKTFUNK_ADAPTER` remains the session binary's env override).
|
|
|
|
use windows::core::Interface;
|
|
use windows::Win32::Graphics::Dxgi::{CreateDXGIFactory1, IDXGIAdapter, IDXGIFactory1};
|
|
|
|
/// The adapter's human-readable description.
|
|
fn adapter_name(adapter: &IDXGIAdapter) -> String {
|
|
// SAFETY: a read-only COM call on the live `adapter` borrow, filling a descriptor returned by
|
|
// value; `&IDXGIAdapter` is a reference-counted wrapper, so the borrow IS the liveness.
|
|
unsafe {
|
|
adapter
|
|
.GetDesc()
|
|
.map(|d| {
|
|
String::from_utf16_lossy(&d.Description)
|
|
.trim_end_matches('\0')
|
|
.to_string()
|
|
})
|
|
.unwrap_or_else(|_| "<unknown adapter>".into())
|
|
}
|
|
}
|
|
|
|
/// Every DXGI adapter, in enumeration order.
|
|
fn all_adapters() -> Vec<IDXGIAdapter> {
|
|
// SAFETY: DXGI factory creation takes no pointer and returns an owned factory or an error,
|
|
// matched on below before anything uses it.
|
|
let factory: IDXGIFactory1 = match unsafe { CreateDXGIFactory1() } {
|
|
Ok(f) => f,
|
|
Err(_) => return Vec::new(),
|
|
};
|
|
let mut v = Vec::new();
|
|
let mut i = 0u32;
|
|
// SAFETY: a COM call on the live factory above; it takes an index and yields an owned adapter,
|
|
// and the `Ok` pattern is what proves one came back.
|
|
while let Ok(a) = unsafe { factory.EnumAdapters1(i) } {
|
|
i += 1;
|
|
if let Ok(a) = a.cast::<IDXGIAdapter>() {
|
|
v.push(a);
|
|
}
|
|
}
|
|
v
|
|
}
|
|
|
|
/// Descriptions of the real (hardware, non-WARP) GPUs — the Settings GPU picker's option list.
|
|
/// The picker only shows when this has more than one entry.
|
|
///
|
|
/// **Deduplicated by description**, because the description IS the identity everywhere
|
|
/// downstream: the pick is persisted as that string (`Settings::adapter`) and matched by
|
|
/// name in the session binary (`PUNKTFUNK_VK_ADAPTER`). So two entries with the same name
|
|
/// are one selectable choice however many times DXGI enumerates them — listing it twice
|
|
/// only offers the user a meaningless coin flip. Seen live on an Intel Arc laptop
|
|
/// (2026-07-19), whose Vulkan ICD likewise enumerates the one physical iGPU twice.
|
|
pub fn adapter_names() -> Vec<String> {
|
|
const DXGI_ADAPTER_FLAG_SOFTWARE: u32 = 2; // dxgi.h; not in this windows-rs feature set
|
|
let mut names: Vec<String> = Vec::new();
|
|
for a in all_adapters() {
|
|
let desc1 = a
|
|
.cast::<windows::Win32::Graphics::Dxgi::IDXGIAdapter1>()
|
|
// SAFETY: a read-only COM call on the adapter just cast, filling a descriptor by value.
|
|
.and_then(|a1| unsafe { a1.GetDesc1() })
|
|
.ok();
|
|
let name = adapter_name(&a);
|
|
// Forensics for the next duplicate/oddity report — which adapters DXGI actually
|
|
// returned, and whether the repeats share a LUID (one adapter enumerated twice)
|
|
// or are distinct devices that merely present the same description.
|
|
if let Some(d) = &desc1 {
|
|
tracing::debug!(
|
|
name = %name,
|
|
luid = format!("{:08x}-{:08x}", d.AdapterLuid.HighPart, d.AdapterLuid.LowPart),
|
|
vendor = format_args!("{:#06x}", d.VendorId),
|
|
device = format_args!("{:#06x}", d.DeviceId),
|
|
flags = d.Flags,
|
|
"DXGI adapter"
|
|
);
|
|
}
|
|
if desc1.is_some_and(|d| d.Flags & DXGI_ADAPTER_FLAG_SOFTWARE != 0) {
|
|
continue; // WARP / software renderer — never a streaming target
|
|
}
|
|
if !names.contains(&name) {
|
|
names.push(name);
|
|
}
|
|
}
|
|
names
|
|
}
|