diff --git a/CHANGELOG.md b/CHANGELOG.md index c3d16f2830..8f29283d87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,7 @@ By @teoxoy in [#4185](https://github.com/gfx-rs/wgpu/pull/4185) - Add `gles_minor_version` field to `wgpu::InstanceDescriptor`. By @PJB3005 in [#3998](https://github.com/gfx-rs/wgpu/pull/3998) - Re-export Naga. By @exrook in [#4172](https://github.com/gfx-rs/wgpu/pull/4172) +- Add WinUI 3 SwapChainPanel support. By @ddrboxman in [#4191](https://github.com/gfx-rs/wgpu/pull/4191) ### Changes diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 9fc198373d..374ea1a15d 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -656,6 +656,34 @@ impl Global { id.0 } + #[cfg(all(feature = "dx12", windows))] + /// # Safety + /// + /// The swap_chain_panel must be valid and able to be used to make a swapchain with. + pub unsafe fn instance_create_surface_from_swap_chain_panel( + &self, + swap_chain_panel: *mut std::ffi::c_void, + id_in: Input, + ) -> SurfaceId { + profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel"); + + let surface = Surface { + presentation: None, + #[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))] + vulkan: None, + dx12: self.instance.dx12.as_ref().map(|inst| HalSurface { + raw: unsafe { inst.create_surface_from_swap_chain_panel(swap_chain_panel as _) }, + }), + dx11: None, + #[cfg(feature = "gles")] + gl: None, + }; + + let mut token = Token::root(); + let id = self.surfaces.prepare(id_in).assign(surface, &mut token); + id.0 + } + pub fn surface_drop(&self, id: SurfaceId) { profiling::scope!("Surface::drop"); log::trace!("Surface::drop {id:?}"); diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index 3959deeccd..269dcd267c 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -580,7 +580,9 @@ impl crate::Adapter for super::Adapter { None } } - SurfaceTarget::Visual(_) | SurfaceTarget::SurfaceHandle(_) => None, + SurfaceTarget::Visual(_) + | SurfaceTarget::SurfaceHandle(_) + | SurfaceTarget::SwapChainPanel(_) => None, } }; diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 3480384384..4568ca34d6 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -124,6 +124,21 @@ impl Instance { swap_chain: None, } } + + pub unsafe fn create_surface_from_swap_chain_panel( + &self, + swap_chain_panel: *mut types::ISwapChainPanelNative, + ) -> Surface { + Surface { + factory: self.factory.clone(), + factory_media: self.factory_media.clone(), + target: SurfaceTarget::SwapChainPanel(unsafe { + d3d12::ComPtr::from_raw(swap_chain_panel) + }), + supports_allow_tearing: self.supports_allow_tearing, + swap_chain: None, + } + } } unsafe impl Send for Instance {} @@ -145,6 +160,7 @@ enum SurfaceTarget { WndHandle(windef::HWND), Visual(d3d12::ComPtr), SurfaceHandle(winnt::HANDLE), + SwapChainPanel(d3d12::ComPtr), } pub struct Surface { @@ -667,7 +683,7 @@ impl crate::Surface for Surface { flags, }; let swap_chain1 = match self.target { - SurfaceTarget::Visual(_) => { + SurfaceTarget::Visual(_) | SurfaceTarget::SwapChainPanel(_) => { profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition"); self.factory .unwrap_factory2() @@ -725,6 +741,17 @@ impl crate::Surface for Surface { )); } } + &SurfaceTarget::SwapChainPanel(ref swap_chain_panel) => { + if let Err(err) = + unsafe { swap_chain_panel.SetSwapChain(swap_chain1.as_ptr()) } + .into_result() + { + log::error!("Unable to SetSwapChain: {}", err); + return Err(crate::SurfaceError::Other( + "ISwapChainPanelNative::SetSwapChain", + )); + } + } } match unsafe { swap_chain1.cast::() }.into_result() { @@ -749,7 +776,9 @@ impl crate::Surface for Surface { ) }; } - SurfaceTarget::Visual(_) | SurfaceTarget::SurfaceHandle(_) => {} + SurfaceTarget::Visual(_) + | SurfaceTarget::SurfaceHandle(_) + | SurfaceTarget::SwapChainPanel(_) => {} } unsafe { swap_chain.SetMaximumFrameLatency(config.swap_chain_size) }; diff --git a/wgpu-hal/src/dx12/types.rs b/wgpu-hal/src/dx12/types.rs index dec4e71337..b4ad38324a 100644 --- a/wgpu-hal/src/dx12/types.rs +++ b/wgpu-hal/src/dx12/types.rs @@ -1,6 +1,15 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] +// use here so that the recursive RIDL macro can find the crate +use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl}; +use winapi::RIDL; + +RIDL! {#[uuid(0x63aad0b8, 0x7c24, 0x40ff, 0x85, 0xa8, 0x64, 0x0d, 0x94, 0x4c, 0xc3, 0x25)] +interface ISwapChainPanelNative(ISwapChainPanelNativeVtbl): IUnknown(IUnknownVtbl) { + fn SetSwapChain(swapChain: *const winapi::shared::dxgi1_2::IDXGISwapChain1,) -> winapi::um::winnt::HRESULT, +}} + winapi::ENUM! { enum D3D12_VIEW_INSTANCING_TIER { D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED = 0, diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index e8776f881a..bfdd1909ab 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -287,6 +287,21 @@ impl Context { } } + #[cfg(target_os = "windows")] + pub unsafe fn create_surface_from_swap_chain_panel( + &self, + swap_chain_panel: *mut std::ffi::c_void, + ) -> Surface { + let id = unsafe { + self.0 + .instance_create_surface_from_swap_chain_panel(swap_chain_panel, ()) + }; + Surface { + id, + configured_device: Mutex::default(), + } + } + fn handle_error( &self, sink_mutex: &Mutex, diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index f5323a6e34..0e6037e493 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -2027,6 +2027,31 @@ impl Instance { } } + /// Creates a surface from `SwapChainPanel`. + /// + /// # Safety + /// + /// - visual must be a valid SwapChainPanel to create a surface upon. + #[cfg(target_os = "windows")] + pub unsafe fn create_surface_from_swap_chain_panel( + &self, + swap_chain_panel: *mut std::ffi::c_void, + ) -> Surface { + let surface = unsafe { + self.context + .as_any() + .downcast_ref::() + .unwrap() + .create_surface_from_swap_chain_panel(swap_chain_panel) + }; + Surface { + context: Arc::clone(&self.context), + id: ObjectId::from(surface.id()), + data: Box::new(surface), + config: Mutex::new(None), + } + } + /// Creates a surface from a `web_sys::HtmlCanvasElement`. /// /// The `canvas` argument must be a valid `` element to