diff --git a/deno_webgpu/lib.rs b/deno_webgpu/lib.rs index 56c475cd8ff..84029e030c6 100644 --- a/deno_webgpu/lib.rs +++ b/deno_webgpu/lib.rs @@ -394,6 +394,7 @@ pub fn op_webgpu_request_adapter( backend_options: wgpu_types::BackendOptions { dx12: wgpu_types::Dx12BackendOptions { shader_compiler: wgpu_types::Dx12Compiler::Fxc, + use_dcomp: false, }, gl: wgpu_types::GlBackendOptions { gles_minor_version: wgpu_types::Gles3MinorVersion::default(), diff --git a/tests/src/init.rs b/tests/src/init.rs index 67b33c0f19b..116d205921c 100644 --- a/tests/src/init.rs +++ b/tests/src/init.rs @@ -43,6 +43,7 @@ pub fn initialize_instance(backends: wgpu::Backends, force_fxc: bool) -> Instanc backend_options: wgpu::BackendOptions { dx12: wgpu::Dx12BackendOptions { shader_compiler: dx12_shader_compiler, + use_dcomp: false, }, gl: wgpu::GlBackendOptions { gles_minor_version }, }, diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 6b1e721d4ef..e9b540596ed 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -78,6 +78,7 @@ impl Instance { .dx12 .shader_compiler .clone(), + dx12_use_dcomp: instance_desc.backend_options.dx12.use_dcomp, gles_minor_version: instance_desc.backend_options.gl.gles_minor_version, }; diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 7287246dfcc..2392589bb73 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -82,6 +82,8 @@ dx12 = [ "windows/Win32_Graphics_Direct3D_Fxc", "windows/Win32_Graphics_Direct3D_Dxc", "windows/Win32_Graphics_Direct3D", + "windows/Win32_Graphics_Direct3D11", + "windows/Win32_Graphics_Direct3D11on12", "windows/Win32_Graphics_Direct3D12", "windows/Win32_Graphics_DirectComposition", "windows/Win32_Graphics_Dxgi_Common", diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 22612036825..c3843de4309 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -98,6 +98,7 @@ impl Example { flags: wgt::InstanceFlags::from_build_config().with_env(), // Can't rely on having DXC available, so use FXC instead dx12_shader_compiler: wgt::Dx12Compiler::Fxc, + dx12_use_dcomp: false, gles_minor_version: wgt::Gles3MinorVersion::default(), }; let instance = unsafe { A::Instance::init(&instance_desc)? }; diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index 3e048e9396c..e82520fb7b1 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -243,6 +243,7 @@ impl Example { dxc_path: "dxcompiler.dll".to_string(), dxil_path: "dxil.dll".to_string(), }, + dx12_use_dcomp: false, gles_minor_version: wgt::Gles3MinorVersion::default(), }; let instance = unsafe { A::Instance::init(&instance_desc)? }; diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 3a6ebd95d37..66a755a6baf 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -787,7 +787,10 @@ impl crate::Adapter for super::Adapter { ) -> Option { let current_extent = { match surface.target { - SurfaceTarget::WndHandle(wnd_handle) => { + SurfaceTarget::WndHandle(wnd_handle) + | SurfaceTarget::VisualFromWndHandle { + handle: wnd_handle, .. + } => { let mut rect = Default::default(); if unsafe { WindowsAndMessaging::GetClientRect(wnd_handle, &mut rect) }.is_ok() { @@ -831,6 +834,7 @@ impl crate::Adapter for super::Adapter { composite_alpha_modes: match surface.target { SurfaceTarget::WndHandle(_) => vec![wgt::CompositeAlphaMode::Opaque], SurfaceTarget::Visual(_) + | SurfaceTarget::VisualFromWndHandle { .. } | SurfaceTarget::SurfaceHandle(_) | SurfaceTarget::SwapChainPanel(_) => vec![ wgt::CompositeAlphaMode::Auto, diff --git a/wgpu-hal/src/dx12/instance.rs b/wgpu-hal/src/dx12/instance.rs index 64b32b772da..81f4b90cfc6 100644 --- a/wgpu-hal/src/dx12/instance.rs +++ b/wgpu-hal/src/dx12/instance.rs @@ -108,6 +108,7 @@ impl crate::Instance for super::Instance { library: Arc::new(lib_main), _lib_dxgi: lib_dxgi, supports_allow_tearing, + use_dcomp: desc.dx12_use_dcomp, flags: desc.flags, dxc_container, }) @@ -119,14 +120,26 @@ impl crate::Instance for super::Instance { window_handle: raw_window_handle::RawWindowHandle, ) -> Result { match window_handle { - raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface { - factory: self.factory.clone(), - factory_media: self.factory_media.clone(), + raw_window_handle::RawWindowHandle::Win32(handle) => { // https://github.com/rust-windowing/raw-window-handle/issues/171 - target: SurfaceTarget::WndHandle(Foundation::HWND(handle.hwnd.get() as *mut _)), - supports_allow_tearing: self.supports_allow_tearing, - swap_chain: RwLock::new(None), - }), + let handle = Foundation::HWND(handle.hwnd.get() as *mut _); + let target = if self.use_dcomp { + SurfaceTarget::VisualFromWndHandle { + handle, + dcomp_state: Default::default(), + } + } else { + SurfaceTarget::WndHandle(handle) + }; + Ok(super::Surface { + factory: self.factory.clone(), + factory_media: self.factory_media.clone(), + + target, + supports_allow_tearing: self.supports_allow_tearing, + swap_chain: RwLock::new(None), + }) + } _ => Err(crate::InstanceError::new(format!( "window handle {window_handle:?} is not a Win32 handle" ))), diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 809d53c74d9..31c4f14335b 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -52,7 +52,7 @@ use windows::{ core::{Free, Interface}, Win32::{ Foundation, - Graphics::{Direct3D, Direct3D12, DirectComposition, Dxgi}, + Graphics::{Direct3D, Direct3D11, Direct3D11on12, Direct3D12, DirectComposition, Dxgi}, System::Threading, }, }; @@ -410,6 +410,7 @@ pub struct Instance { factory_media: Option, library: Arc, supports_allow_tearing: bool, + use_dcomp: bool, _lib_dxgi: DxgiLib, flags: wgt::InstanceFlags, dxc_container: Option>, @@ -479,9 +480,21 @@ struct SwapChain { size: wgt::Extent3d, } +struct DCompState { + visual: DirectComposition::IDCompositionVisual, + device: DirectComposition::IDCompositionDevice, + // Must be kept alive but is otherwise unused after initialization. + _target: DirectComposition::IDCompositionTarget, +} + enum SurfaceTarget { /// Borrowed, lifetime externally managed WndHandle(Foundation::HWND), + /// `handle` is borrowed, lifetime externally managed + VisualFromWndHandle { + handle: Foundation::HWND, + dcomp_state: RwLock>, + }, Visual(DirectComposition::IDCompositionVisual), /// Borrowed, lifetime externally managed SurfaceHandle(Foundation::HANDLE), @@ -1137,7 +1150,9 @@ impl crate::Surface for Surface { Flags: flags.0 as u32, }; let swap_chain1 = match self.target { - SurfaceTarget::Visual(_) | SurfaceTarget::SwapChainPanel(_) => { + SurfaceTarget::Visual(_) + | SurfaceTarget::VisualFromWndHandle { .. } + | SurfaceTarget::SwapChainPanel(_) => { profiling::scope!("IDXGIFactory2::CreateSwapChainForComposition"); unsafe { self.factory.CreateSwapChainForComposition( @@ -1184,6 +1199,70 @@ impl crate::Surface for Surface { match &self.target { SurfaceTarget::WndHandle(_) | SurfaceTarget::SurfaceHandle(_) => {} + SurfaceTarget::VisualFromWndHandle { + handle, + dcomp_state, + } => unsafe { + macro_rules! call { + ($name:literal, $e:expr) => {{ + profiling::scope!($name); + ($e).map_err(|_| crate::SurfaceError::Other($name))? + }}; + } + + // Initialize the window-linked DirectComposition state + // if we haven't done so already. + let mut dcomp_state = dcomp_state.write(); + let dcomp_state = match dcomp_state.as_mut() { + Some(s) => s, + None => { + let mut d3d11_device = None; + call!( + "Direct3D11on12::D3D11On12CreateDevice", + Direct3D11on12::D3D11On12CreateDevice( + &device.raw, + Direct3D11::D3D11_CREATE_DEVICE_BGRA_SUPPORT.0, + None, + None, + 0, + Some(&mut d3d11_device), + None, + None, + ) + ); + let d3d11_device = d3d11_device.unwrap(); + let dxgi_device: Dxgi::IDXGIDevice = + call!("IDXGIDevice::QueryInterface", d3d11_device.cast()); + let dcomp_device: DirectComposition::IDCompositionDevice = call!( + "DirectComposition::DCompositionCreateDevice", + DirectComposition::DCompositionCreateDevice(&dxgi_device) + ); + let target = call!( + "IDCompositionDevice::CreateTargetForHwnd", + dcomp_device.CreateTargetForHwnd(*handle, false) + ); + let visual = call!( + "IDCompositionDevice::CreateVisual", + dcomp_device.CreateVisual() + ); + call!("IDCompositionTarget::SetRoot", target.SetRoot(&visual)); + + dcomp_state.insert(DCompState { + visual, + device: dcomp_device, + _target: target, + }) + } + }; + + // Set the new swap chain as the content for the backing visual + // and commit the changes to the composition visual tree. + call!( + "IDCompositionVisual::SetContent", + dcomp_state.visual.SetContent(&swap_chain1) + ); + call!("IDCompositionDevice::Commit", dcomp_state.device.Commit()); + }, SurfaceTarget::Visual(visual) => { if let Err(err) = unsafe { visual.SetContent(&swap_chain1) } { log::error!("Unable to SetContent: {err}"); @@ -1221,6 +1300,7 @@ impl crate::Surface for Surface { .into_device_result("MakeWindowAssociation")?; } SurfaceTarget::Visual(_) + | SurfaceTarget::VisualFromWndHandle { .. } | SurfaceTarget::SurfaceHandle(_) | SurfaceTarget::SwapChainPanel(_) => {} } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 4cc0ef80bdd..5ef18d0afc3 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -1752,6 +1752,7 @@ pub struct InstanceDescriptor<'a> { pub name: &'a str, pub flags: wgt::InstanceFlags, pub dx12_shader_compiler: wgt::Dx12Compiler, + pub dx12_use_dcomp: bool, pub gles_minor_version: wgt::Gles3MinorVersion, } diff --git a/wgpu-types/src/instance.rs b/wgpu-types/src/instance.rs index a48aabbd4ad..04cebf849a8 100644 --- a/wgpu-types/src/instance.rs +++ b/wgpu-types/src/instance.rs @@ -243,6 +243,8 @@ impl GlBackendOptions { pub struct Dx12BackendOptions { /// Which DX12 shader compiler to use. pub shader_compiler: Dx12Compiler, + /// Whether to use DirectComposition for managing presentation. + pub use_dcomp: bool, } impl Dx12BackendOptions { @@ -254,6 +256,7 @@ impl Dx12BackendOptions { let compiler = Dx12Compiler::from_env().unwrap_or_default(); Self { shader_compiler: compiler, + use_dcomp: false, } } @@ -263,7 +266,10 @@ impl Dx12BackendOptions { #[must_use] pub fn with_env(self) -> Self { let shader_compiler = self.shader_compiler.with_env(); - Self { shader_compiler } + Self { + shader_compiler, + use_dcomp: false, + } } }