feat(windows-drivers): pf-vdisplay STEP 0 scaffold + std-under-UMDF link gate
apple / swift (push) Failing after 2s
apple / screenshots (push) Has been skipped
windows-drivers / probe-and-proto (push) Successful in 19s
windows-drivers / driver-build (push) Successful in 1m5s
windows-host / package (push) Successful in 5m25s
android / android (push) Has been cancelled
ci / web (push) Successful in 51s
ci / docs-site (push) Successful in 1m12s
ci / rust (push) Successful in 4m8s
deb / build-publish (push) Successful in 2m18s
decky / build-publish (push) Successful in 12s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
ci / bench (push) Successful in 4m47s
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
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m23s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 9m47s
docker / deploy-docs (push) Successful in 18s

M1 step 2 begins. Add the wdk-iddcx (lib, re-exports wdk_sys::iddcx) + pf-vdisplay
(cdylib) workspace members. pf-vdisplay STEP 0 = DriverEntry + WdfDeviceCreate
skeleton + a #[used] _std_link_gate forcing std::thread + OwnedHandle to link, so
the build proves the std surface resolves under the wdk-build UMDF link settings
(kernel32 is /NODEFAULTLIB - std must come via OneCoreUAP). If std fails to link
here, the SwapChainProcessor worker-thread design needs a CreateThread shim before
any callback work (port-plan critique gap #9).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-24 15:49:03 +00:00
parent f652617f30
commit d7a9fbf0b6
7 changed files with 147 additions and 1 deletions
+18
View File
@@ -394,6 +394,17 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pf-vdisplay"
version = "0.0.1"
dependencies = [
"pf-vdisplay-proto",
"wdk",
"wdk-build",
"wdk-iddcx",
"wdk-sys",
]
[[package]] [[package]]
name = "pf-vdisplay-proto" name = "pf-vdisplay-proto"
version = "0.0.1" version = "0.0.1"
@@ -735,6 +746,13 @@ dependencies = [
"windows", "windows",
] ]
[[package]]
name = "wdk-iddcx"
version = "0.0.1"
dependencies = [
"wdk-sys",
]
[[package]] [[package]]
name = "wdk-macros" name = "wdk-macros"
version = "0.5.1" version = "0.5.1"
+2 -1
View File
@@ -7,7 +7,7 @@
# crates/pf-vdisplay-proto from the main tree. # crates/pf-vdisplay-proto from the main tree.
[workspace] [workspace]
resolver = "2" resolver = "2"
members = ["wdk-probe"] members = ["wdk-probe", "wdk-iddcx", "pf-vdisplay"]
[workspace.package] [workspace.package]
edition = "2024" edition = "2024"
@@ -19,6 +19,7 @@ publish = false
wdk = "0.4.1" wdk = "0.4.1"
wdk-sys = "0.5.1" wdk-sys = "0.5.1"
wdk-build = "0.5.1" wdk-build = "0.5.1"
wdk-iddcx = { path = "wdk-iddcx" }
pf-vdisplay-proto = { path = "../../../crates/pf-vdisplay-proto" } pf-vdisplay-proto = { path = "../../../crates/pf-vdisplay-proto" }
# Vendored windows-drivers-rs 0.5.1 (the published, self-contained crates) + an added `iddcx` # Vendored windows-drivers-rs 0.5.1 (the published, self-contained crates) + an added `iddcx`
@@ -0,0 +1,26 @@
# pf-vdisplay — the all-Rust UMDF IddCx virtual-display driver (M1 step-2 rewrite onto wdk-sys + the
# owned pf-vdisplay-proto ABI). Replaces the vendored-binding oracle at packaging/windows/vdisplay-driver/
# (deleted once on-glass parity is reached, per docs/windows-host-rewrite.md §14 STEP 8).
[package]
name = "pf-vdisplay"
edition.workspace = true
version.workspace = true
license.workspace = true
publish = false
[package.metadata.wdk.driver-model]
driver-type = "UMDF"
umdf-version-major = 2
target-umdf-version-minor = 31
[lib]
crate-type = ["cdylib"]
[build-dependencies]
wdk-build.workspace = true
[dependencies]
wdk.workspace = true
wdk-sys = { workspace = true, features = ["iddcx"] }
wdk-iddcx.workspace = true
pf-vdisplay-proto.workspace = true
@@ -0,0 +1,6 @@
//! Emits the WDK link flags for the cdylib (wdk-build). STEP 0 needs only the WDF stub link + the
//! `/INTEGRITYCHECK` that the CI step clears; `IddCxStub` (+ `IddMinimumVersionRequired`) is added in
//! STEP 2 when the driver actually calls IddCx — see wdk-probe/build.rs for the glob recipe.
fn main() -> Result<(), wdk_build::ConfigError> {
wdk_build::configure_wdk_binary_build()
}
@@ -0,0 +1,70 @@
//! pf-vdisplay — the all-Rust UMDF IddCx virtual-display driver (M1 step-2 rewrite, on wdk-sys + the
//! owned pf-vdisplay-proto ABI). See docs/windows-host-rewrite.md §14 for the full port plan.
//!
//! STEP 0 (this commit): the workspace scaffold + the std-under-UMDF LINK GATE. DriverEntry →
//! WdfDriverCreate → (EvtDeviceAdd) WdfDeviceCreate, plus a `#[used]` probe that forces `std::thread`
//! + `OwnedHandle` to link — the SwapChainProcessor (STEP 5) depends on both, and the wdk-build UMDF
//! link settings `/NODEFAULTLIB:kernel32.lib`, so std must resolve via OneCoreUAP. If this fails to
//! link, the worker-thread/handle design needs a CreateThread shim BEFORE any callback work (port-plan
//! critique gap #9). The adapter/monitor/swapchain/IDD-push logic lands in STEP 2-6.
#![allow(non_snake_case, clippy::missing_safety_doc)]
use wdk_sys::{
call_unsafe_wdf_function_binding, NTSTATUS, PCUNICODE_STRING, PDRIVER_OBJECT, PWDFDEVICE_INIT,
ULONG, WDFDEVICE, WDFDRIVER, WDF_DRIVER_CONFIG, WDF_NO_HANDLE, WDF_NO_OBJECT_ATTRIBUTES,
};
const STATUS_SUCCESS: NTSTATUS = 0;
/// STEP-0 link gate (port-plan critique #9). Forces `std::thread` + `std::os::windows::io::OwnedHandle`
/// to be linked into the UMDF cdylib so STEP 0's `cargo build` actually proves the std surface resolves
/// under the wdk-build link settings (kernel32 is `/NODEFAULTLIB`'d → std must come via OneCoreUAP).
/// Never called; `#[used]` keeps the symbol so the linker pulls std. Also touches `wdk-iddcx` to prove
/// the pf-vdisplay → wdk-iddcx → wdk-sys/iddcx dependency graph resolves.
fn _std_link_gate() {
use std::os::windows::io::OwnedHandle;
let t = std::thread::spawn(|| 0u32);
let _ = t.join();
let _drop_owned: fn(OwnedHandle) = core::mem::drop;
// touch the iddcx surface via wdk-iddcx (forces the feature-enabled dep graph)
let _adapter: Option<wdk_iddcx::iddcx::IDDCX_ADAPTER> = None;
}
#[used]
static _STD_LINK_GATE: fn() = _std_link_gate;
#[unsafe(export_name = "DriverEntry")]
pub unsafe extern "system" fn driver_entry(
driver: PDRIVER_OBJECT,
registry_path: PCUNICODE_STRING,
) -> NTSTATUS {
// SAFETY: zeroed then Size + the device-add callback set, per the WDF_DRIVER_CONFIG contract.
let mut config: WDF_DRIVER_CONFIG = unsafe { core::mem::zeroed() };
config.Size = core::mem::size_of::<WDF_DRIVER_CONFIG>() as ULONG;
config.EvtDriverDeviceAdd = Some(evt_device_add);
// SAFETY: driver + registry_path are loader-provided; config is valid for the call.
unsafe {
call_unsafe_wdf_function_binding!(
WdfDriverCreate,
driver,
registry_path,
WDF_NO_OBJECT_ATTRIBUTES,
&mut config,
WDF_NO_HANDLE.cast::<WDFDRIVER>()
)
}
}
extern "C" fn evt_device_add(_driver: WDFDRIVER, mut device_init: PWDFDEVICE_INIT) -> NTSTATUS {
let mut device: WDFDEVICE = core::ptr::null_mut();
// SAFETY: device_init is the framework-provided init; attributes null; device receives the handle.
let _ = unsafe {
call_unsafe_wdf_function_binding!(
WdfDeviceCreate,
&mut device_init,
WDF_NO_OBJECT_ATTRIBUTES,
&mut device
)
};
STATUS_SUCCESS
}
@@ -0,0 +1,14 @@
# Safe-ish typed wrappers over the wdk-sys IddCx DDIs (table dispatch). Graduates the proven dispatch
# from wdk-probe/src/iddcx_rt.rs (M1 step 1) into a reusable crate the pf-vdisplay driver depends on.
# A plain lib (rlib) — no build.rs; it rides on wdk-sys's iddcx bindgen.
[package]
name = "wdk-iddcx"
edition.workspace = true
version.workspace = true
license.workspace = true
publish = false
[lib]
[dependencies]
wdk-sys = { workspace = true, features = ["iddcx"] }
@@ -0,0 +1,11 @@
//! Safe-ish typed wrappers over the wdk-sys IddCx DDIs, dispatched through the `IddFunctions` table
//! (indexed by `_IDDFUNCENUM::<Name>TableIndex`, with `IddDriverGlobals` as the implicit first arg) —
//! the same model wdk-sys uses for WDF. Graduates the proven dispatch from `wdk-probe/src/iddcx_rt.rs`
//! (M1 step 1) into the crate the pf-vdisplay driver builds on.
//!
//! STEP 0: re-export the wdk-sys `iddcx` module so the crate + the `iddcx` feature resolve in the
//! workspace. STEP 1 adds the 11 typed DDI wrappers (one fixed `(_IDDFUNCENUM index, PFN_*)` pair per
//! site) + `is_nt_error`/`other_is_error` + the inbound `PFN_IDD_CX_*` callback-type re-exports.
#![no_std]
pub use wdk_sys::iddcx;