Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WinUI 3 SwapChainPanel support #4191

Merged
merged 5 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -666,7 +682,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 @@ -724,6 +740,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 @@ -748,7 +775,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