feat(windows): pf-vdisplay — all-Rust IddCx virtual display (replaces SudoVDA)
P1 done: a pure-Rust UMDF2 IddCx driver, drop-in compatible with the host's
existing vdisplay/sudovda.rs control plane (the {e5bcc234} interface + the
SudoVDA IOCTL ABI), so the host drives it unchanged. Validated streaming on
glass at 5120x1440@240 — steady 240 fps, ~2.4 ms encode, clean teardown, full
parity with SudoVDA.
- Vendored wdf-umdf-sys / wdf-umdf bindgen crates (MIT, from virtual-display-rs)
+ the SDK-version build.rs fix that resolves the IddCxStub lib path by the WDK
version actually containing um\x64\iddcx, not the max base SDK.
- pf-vdisplay crate: entry/callbacks/context/control/monitor/edid/
swap_chain_processor. Our OWN 128-byte EDID (manufacturer PNK, product
punktfunk — no SudoVDA bytes), a real swap-chain drain (faithful vdd port,
required so DWM keeps compositing), the SudoVDA-compatible IOCTL control plane
(ADD/REMOVE/PING/GET_WATCHDOG/GET_VERSION/SET_RENDER_ADAPTER) + a watchdog that
tears down orphaned monitors when the host stops pinging.
- deploy-dev.ps1: stage + sign + stampinf (date.time DriverVer) + Inf2Cat +
install, codifying the "bump DriverVer or pnputil keeps the old binary" gotcha.
- docs/windows-virtual-display-rust-port.md: investigation, the on-glass
validation, and the two traps that cost time (Session-0 measurement +
accumulated device-state needing a reboot).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
use windows::{
|
||||
core::Error,
|
||||
Win32::{
|
||||
Foundation::LUID,
|
||||
Graphics::{
|
||||
Direct3D::D3D_DRIVER_TYPE_UNKNOWN,
|
||||
Direct3D11::{
|
||||
D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
D3D11_CREATE_DEVICE_PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY,
|
||||
D3D11_CREATE_DEVICE_SINGLETHREADED, D3D11_SDK_VERSION,
|
||||
},
|
||||
Dxgi::{CreateDXGIFactory2, IDXGIAdapter1, IDXGIFactory5, DXGI_CREATE_FACTORY_FLAGS},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Direct3DError {
|
||||
#[error("Direct3DError({0:?})")]
|
||||
Win32(#[from] Error),
|
||||
#[error("Direct3DError(\"{0}\")")]
|
||||
Other(&'static str),
|
||||
}
|
||||
|
||||
impl From<&'static str> for Direct3DError {
|
||||
fn from(value: &'static str) -> Self {
|
||||
Direct3DError::Other(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Direct3DDevice {
|
||||
// The following are already refcounted, so they're safe to use directly without additional drop impls
|
||||
_dxgi_factory: IDXGIFactory5,
|
||||
_adapter: IDXGIAdapter1,
|
||||
pub device: ID3D11Device,
|
||||
_device_context: ID3D11DeviceContext,
|
||||
}
|
||||
|
||||
impl Direct3DDevice {
|
||||
pub fn init(adapter_luid: LUID) -> Result<Self, Direct3DError> {
|
||||
let dxgi_factory =
|
||||
unsafe { CreateDXGIFactory2::<IDXGIFactory5>(DXGI_CREATE_FACTORY_FLAGS(0))? };
|
||||
|
||||
let adapter = unsafe { dxgi_factory.EnumAdapterByLuid::<IDXGIAdapter1>(adapter_luid)? };
|
||||
|
||||
let mut device = None;
|
||||
let mut device_context = None;
|
||||
|
||||
unsafe {
|
||||
D3D11CreateDevice(
|
||||
&adapter,
|
||||
D3D_DRIVER_TYPE_UNKNOWN,
|
||||
None,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT
|
||||
| D3D11_CREATE_DEVICE_SINGLETHREADED
|
||||
| D3D11_CREATE_DEVICE_PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY,
|
||||
None,
|
||||
D3D11_SDK_VERSION,
|
||||
Some(&mut device),
|
||||
None,
|
||||
Some(&mut device_context),
|
||||
)?;
|
||||
}
|
||||
|
||||
let device = device.ok_or("ID3D11Device not found")?;
|
||||
let device_context = device_context.ok_or("ID3D11DeviceContext not found")?;
|
||||
|
||||
Ok(Self {
|
||||
_dxgi_factory: dxgi_factory,
|
||||
_adapter: adapter,
|
||||
device,
|
||||
_device_context: device_context,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user