feat(windows-drivers): STEP 5 — SwapChainProcessor + Direct3DDevice (swap-chain drain)
apple / swift (push) Failing after 1s
apple / screenshots (push) Has been skipped
windows-drivers / probe-and-proto (push) Successful in 18s
ci / rust (push) Successful in 1m14s
windows-drivers / driver-build (push) Successful in 1m11s
ci / web (push) Successful in 41s
ci / docs-site (push) Successful in 1m1s
android / android (push) Successful in 3m22s
deb / build-publish (push) Successful in 2m37s
decky / build-publish (push) Successful in 11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 6s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
windows-host / package (push) Successful in 5m52s
ci / bench (push) Successful in 4m47s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m28s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m18s
docker / deploy-docs (push) Successful in 17s
apple / swift (push) Failing after 1s
apple / screenshots (push) Has been skipped
windows-drivers / probe-and-proto (push) Successful in 18s
ci / rust (push) Successful in 1m14s
windows-drivers / driver-build (push) Successful in 1m11s
ci / web (push) Successful in 41s
ci / docs-site (push) Successful in 1m1s
android / android (push) Successful in 3m22s
deb / build-publish (push) Successful in 2m37s
decky / build-publish (push) Successful in 11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 6s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
windows-host / package (push) Successful in 5m52s
ci / bench (push) Successful in 4m47s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m28s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m18s
docker / deploy-docs (push) Successful in 17s
The pf-vdisplay driver now consumes the OS swap-chain so a virtual monitor is a usable display rather than a stalled one. Compiles + loads on-glass (no regression: adapter still inits, Status=OK); adversarially reviewed — no blockers, the leak/deadlock invariants preserved. - new swap_chain_processor.rs: a worker thread (MMCSS "Distribution") that binds the render D3D device (IddCxSwapChainSetDevice, single-borrow 60x@50ms retry) then drains the swap-chain (ReleaseAndAcquireBuffer2 -> FinishedProcessingFrame; E_PENDING waits 16ms on the surface event). NO frame publisher yet (STEP 6). RAII terminate+join Drop; the load-bearing top-of-loop terminate check (the oracle's reconnect-leak fix). Fixed a Rust-2021 disjoint- capture bug: `.0` field access bypassed the Sendable Send wrapper -> rebind the whole wrappers. - new direct_3d_device.rs: CreateDXGIFactory2 -> EnumAdapterByLuid(render LUID) -> D3D11CreateDevice; a DEVICE_POOL of one Arc<Direct3DDevice> per render LUID (the NVIDIA-UMD-worker-thread leak fix). - monitor.rs: MonitorObject gains swap_chain_processor; set/take helpers return it for the caller to drop OUTSIDE the MONITOR_MODES lock (dropping joins the worker — must never happen under the lock); remove_monitor/clear_all drop it before IddCxMonitorDeparture. - callbacks.rs: assign_swap_chain spawns the processor (pooled device per RenderAdapterLuid; WdfObjectDelete on D3D-init failure so the OS retries); unassign_swap_chain drops it. Fixed the stale `panic = "abort"` doc (workspace is unwind; the extern "C" boundary aborts on unwind). - Cargo.toml: windows 0.58 + thiserror (both already resolved in the driver lock). The 3 needed swap-chain DDIs were already wrapped in wdk-iddcx; their HRESULT-shaped NTSTATUS is classified by hand (hr>=0 success, 0x8000000A E_PENDING). - Also rustfmt'd the whole driver workspace (it had never been driver-fmt'd). Built via the ultracode flow: STEP-5 map workflow -> agent-implement -> box build (caught the Send-capture bug) -> adversarial-verify-agent -> deploy (loads). Session-1 on-glass validation (the drain loop servicing an ACTIVE monitor) is the next gate — assign_swap_chain only fires under an interactive session. Note for STEP 6: target_id_for_object uses the MONITOR_MODES handle lookup the oracle moved to a WDF context; revisit before target_id keys the shared frame ring. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
//! The IddCx client-config callbacks + the PnP `EvtDeviceD0Entry`.
|
||||
//!
|
||||
//! STEP 2: stubs with the correct PFN signatures (so the config wires up + the driver loads); the real
|
||||
//! mode/EDID logic (STEP 4), adapter init (STEP 3), and swap-chain handoff (STEP 5) fill them in. Every
|
||||
//! callback is `unsafe extern "C"` to match the wdk-sys `PFN_IDD_CX_*` types; with `panic = "abort"`
|
||||
//! (workspace profile) a panic across the FFI boundary aborts rather than being UB. `query_target_info`
|
||||
//! is implemented now because it gates HDR (`HIGH_COLOR_SPACE`) and the adapter (STEP 3) sets FP16.
|
||||
//! The mode/EDID logic (STEP 4), adapter init (STEP 3), and swap-chain handoff (STEP 5) are wired in; the
|
||||
//! `*2`/HDR-metadata/gamma callbacks remain stubs (STEP 7). Every callback is `unsafe extern "C"` to match
|
||||
//! the wdk-sys `PFN_IDD_CX_*` types; a panic unwinding across that `extern "C"` boundary aborts the process
|
||||
//! (Rust >= 1.81 default) rather than being UB. (The swap-chain WORKER is a plain `thread::spawn`, so a
|
||||
//! panic there only unwinds + ends that thread — it must not panic.) `query_target_info` is implemented
|
||||
//! because it gates HDR (`HIGH_COLOR_SPACE`) and the adapter (STEP 3) sets FP16.
|
||||
|
||||
use wdk_sys::iddcx;
|
||||
use wdk_sys::{NTSTATUS, WDFDEVICE, WDFREQUEST};
|
||||
use wdk_sys::{NTSTATUS, WDFDEVICE, WDFOBJECT, WDFREQUEST, call_unsafe_wdf_function_binding};
|
||||
|
||||
use crate::{
|
||||
STATUS_BUFFER_TOO_SMALL, STATUS_INVALID_PARAMETER, STATUS_NOT_FOUND, STATUS_NOT_IMPLEMENTED,
|
||||
@@ -178,16 +179,67 @@ pub unsafe extern "C" fn set_gamma_ramp(
|
||||
STATUS_SUCCESS
|
||||
}
|
||||
|
||||
/// A swap-chain was assigned to the monitor. STEP 5: spawn the `SwapChainProcessor`.
|
||||
/// A swap-chain was assigned to the monitor. STEP 5: spawn the `SwapChainProcessor` that drains it (so
|
||||
/// the monitor is a usable display). Always returns `STATUS_SUCCESS` — on D3D-init failure we delete the
|
||||
/// swap-chain so the OS makes a fresh one and re-assigns (the oracle pattern).
|
||||
pub unsafe extern "C" fn assign_swap_chain(
|
||||
_monitor: iddcx::IDDCX_MONITOR,
|
||||
_p_in: *const iddcx::IDARG_IN_SETSWAPCHAIN,
|
||||
monitor: iddcx::IDDCX_MONITOR,
|
||||
p_in: *const iddcx::IDARG_IN_SETSWAPCHAIN,
|
||||
) -> NTSTATUS {
|
||||
// SAFETY: framework-provided in args, valid for the call.
|
||||
let in_args = unsafe { &*p_in };
|
||||
let swap_chain = in_args.hSwapChain;
|
||||
let render_adapter = in_args.RenderAdapterLuid;
|
||||
let new_frame_event = in_args.hNextSurfaceAvailable;
|
||||
|
||||
// wdk-sys LUID → windows-crate LUID (identical { LowPart: u32, HighPart: i32 } layout). The render
|
||||
// adapter is the GPU the OS picked to render this virtual monitor; the pooled D3D device is keyed by
|
||||
// it (relevant on a hybrid iGPU+dGPU box).
|
||||
let luid = windows::Win32::Foundation::LUID {
|
||||
LowPart: render_adapter.LowPart,
|
||||
HighPart: render_adapter.HighPart,
|
||||
};
|
||||
dbglog!(
|
||||
"[pf-vd] assign_swap_chain: OS render adapter LUID = {:08x}:{:08x}",
|
||||
render_adapter.HighPart,
|
||||
render_adapter.LowPart
|
||||
);
|
||||
|
||||
// FIRST drop any existing processor on this monitor (RAII-joins its worker), OUTSIDE the lock.
|
||||
drop(crate::monitor::take_swap_chain_processor(monitor));
|
||||
|
||||
// The OS target id (stamped on the monitor at creation, after IddCxMonitorArrival) keys the
|
||||
// per-monitor objects STEP 6's host opens. 0 (default) if the monitor isn't found.
|
||||
let target_id = crate::monitor::target_id_for_object(monitor).unwrap_or(0);
|
||||
|
||||
if let Some(device) = crate::direct_3d_device::pooled_device(luid) {
|
||||
let mut processor = crate::swap_chain_processor::SwapChainProcessor::new();
|
||||
processor.run(swap_chain, device, new_frame_event, target_id);
|
||||
// Install on the monitor; drop any processor it replaced (a race lost above) OUTSIDE the lock.
|
||||
drop(crate::monitor::set_swap_chain_processor(monitor, processor));
|
||||
} else {
|
||||
// D3D init failed: delete the swap-chain so the OS generates a fresh one + retries.
|
||||
dbglog!(
|
||||
"[pf-vd] assign_swap_chain: pooled Direct3DDevice unavailable — deleting swap-chain for OS retry"
|
||||
);
|
||||
// SAFETY: `swap_chain` is the framework-provided IddCx swap-chain handle.
|
||||
unsafe {
|
||||
call_unsafe_wdf_function_binding!(WdfObjectDelete, swap_chain as WDFOBJECT);
|
||||
}
|
||||
}
|
||||
STATUS_SUCCESS
|
||||
}
|
||||
|
||||
/// The monitor went inactive. STEP 5: drop the processor (RAII joins the worker thread).
|
||||
pub unsafe extern "C" fn unassign_swap_chain(_monitor: iddcx::IDDCX_MONITOR) -> NTSTATUS {
|
||||
/// The monitor went inactive. STEP 5: drop the processor (RAII joins the worker thread, which deletes the
|
||||
/// swap-chain object before returning).
|
||||
pub unsafe extern "C" fn unassign_swap_chain(monitor: iddcx::IDDCX_MONITOR) -> NTSTATUS {
|
||||
// Take + drop OUTSIDE any lock (the take releases `MONITOR_MODES` before the join).
|
||||
let had = crate::monitor::take_swap_chain_processor(monitor);
|
||||
dbglog!(
|
||||
"[pf-vd] unassign_swap_chain — dropped live processor: {}",
|
||||
had.is_some()
|
||||
);
|
||||
drop(had);
|
||||
STATUS_SUCCESS
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user