Skip to content

Commit

Permalink
Add WinUI 3 SwapChainPanel support (#4191)
Browse files Browse the repository at this point in the history
  • Loading branch information
DDRBoxman authored Oct 11, 2023
1 parent c1748b2 commit 0f7b530
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
28 changes: 28 additions & 0 deletions wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,34 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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<G, SurfaceId>,
) -> 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:?}");
Expand Down
4 changes: 3 additions & 1 deletion wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,9 @@ impl crate::Adapter<super::Api> for super::Adapter {
None
}
}
SurfaceTarget::Visual(_) | SurfaceTarget::SurfaceHandle(_) => None,
SurfaceTarget::Visual(_)
| SurfaceTarget::SurfaceHandle(_)
| SurfaceTarget::SwapChainPanel(_) => None,
}
};

Expand Down
33 changes: 31 additions & 2 deletions wgpu-hal/src/dx12/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand All @@ -145,6 +160,7 @@ enum SurfaceTarget {
WndHandle(windef::HWND),
Visual(d3d12::ComPtr<dcomp::IDCompositionVisual>),
SurfaceHandle(winnt::HANDLE),
SwapChainPanel(d3d12::ComPtr<types::ISwapChainPanelNative>),
}

pub struct Surface {
Expand Down Expand Up @@ -667,7 +683,7 @@ impl crate::Surface<Api> for Surface {
flags,
};
let swap_chain1 = match self.target {
SurfaceTarget::Visual(_) => {
SurfaceTarget::Visual(_) | SurfaceTarget::SwapChainPanel(_) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition");
self.factory
.unwrap_factory2()
Expand Down Expand Up @@ -725,6 +741,17 @@ impl crate::Surface<Api> 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::<dxgi1_4::IDXGISwapChain3>() }.into_result() {
Expand All @@ -749,7 +776,9 @@ impl crate::Surface<Api> for Surface {
)
};
}
SurfaceTarget::Visual(_) | SurfaceTarget::SurfaceHandle(_) => {}
SurfaceTarget::Visual(_)
| SurfaceTarget::SurfaceHandle(_)
| SurfaceTarget::SwapChainPanel(_) => {}
}

unsafe { swap_chain.SetMaximumFrameLatency(config.swap_chain_size) };
Expand Down
9 changes: 9 additions & 0 deletions wgpu-hal/src/dx12/types.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
15 changes: 15 additions & 0 deletions wgpu/src/backend/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ErrorSinkRaw>,
Expand Down
25 changes: 25 additions & 0 deletions wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<crate::backend::Context>()
.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 `<canvas>` element to
Expand Down

0 comments on commit 0f7b530

Please sign in to comment.