Skip to content

Commit

Permalink
Support to create surface from visual on Windows (#2434)
Browse files Browse the repository at this point in the history
* Support to create surface from visual on Windows, add mpo(Multiple Plane Overlay) feature to AdapterInfo

* Expose create_surface_from_visual method

* Fix code style

* Make code more concise

* Revert mpo from AdapterInfo
  • Loading branch information
xiaopengli89 authored Feb 7, 2022
1 parent af83b7f commit 8c35197
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 32 deletions.
24 changes: 24 additions & 0 deletions wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,30 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
id.0
}

#[cfg(dx12)]
pub unsafe fn instance_create_surface_from_visual(
&self,
visual: *mut std::ffi::c_void,
id_in: Input<G, SurfaceId>,
) -> SurfaceId {
profiling::scope!("instance_create_surface_from_visual", "Instance");

let surface = Surface {
presentation: None,
#[cfg(vulkan)]
vulkan: None,
dx12: self.instance.dx12.as_ref().map(|inst| HalSurface {
raw: { inst.create_surface_from_visual(visual as _) },
}),
#[cfg(gl)]
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!("drop", "Surface");
let mut token = Token::root();
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ egl = { package = "khronos-egl", version = "4.1", features = ["static", "no-pkg-
libloading = { version = "0.7", optional = true }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser"] }
winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser", "dcomp"] }
native = { package = "d3d12", version = "0.4.1", features = ["libloading"], optional = true }

[target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies]
Expand Down
27 changes: 16 additions & 11 deletions wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{conv, HResult as _};
use super::{conv, HResult as _, SurfaceTarget};
use std::{mem, sync::Arc, thread};
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_5, minwindef, windef, winerror},
Expand Down Expand Up @@ -389,16 +389,21 @@ impl crate::Adapter<super::Api> for super::Adapter {
surface: &super::Surface,
) -> Option<crate::SurfaceCapabilities> {
let current_extent = {
let mut rect: windef::RECT = mem::zeroed();
if winuser::GetClientRect(surface.wnd_handle, &mut rect) != 0 {
Some(wgt::Extent3d {
width: (rect.right - rect.left) as u32,
height: (rect.bottom - rect.top) as u32,
depth_or_array_layers: 1,
})
} else {
log::warn!("Unable to get the window client rect");
None
match surface.target {
SurfaceTarget::WndHandle(wnd_handle) => {
let mut rect: windef::RECT = mem::zeroed();
if winuser::GetClientRect(wnd_handle, &mut rect) != 0 {
Some(wgt::Extent3d {
width: (rect.right - rect.left) as u32,
height: (rect.bottom - rect.top) as u32,
depth_or_array_layers: 1,
})
} else {
log::warn!("Unable to get the window client rect");
None
}
}
SurfaceTarget::Visual(_) => None,
}
};

Expand Down
4 changes: 2 additions & 2 deletions wgpu-hal/src/dx12/instance.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::HResult as _;
use super::{HResult as _, SurfaceTarget};
use std::{borrow::Cow, slice, sync::Arc};
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_6, winerror},
Expand Down Expand Up @@ -153,7 +153,7 @@ impl crate::Instance<super::Api> for super::Instance {
match has_handle.raw_window_handle() {
raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface {
factory: self.factory,
wnd_handle: handle.hwnd as *mut _,
target: SurfaceTarget::WndHandle(handle.hwnd as *mut _),
swap_chain: None,
}),
_ => Err(crate::InstanceError),
Expand Down
85 changes: 67 additions & 18 deletions wgpu-hal/src/dx12/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use parking_lot::Mutex;
use std::{borrow::Cow, ffi, mem, num::NonZeroU32, ptr, sync::Arc};
use winapi::{
shared::{dxgi, dxgi1_2, dxgi1_4, dxgitype, windef, winerror},
um::{d3d12, synchapi, winbase, winnt},
um::{d3d12, dcomp, synchapi, winbase, winnt},
Interface as _,
};

Expand Down Expand Up @@ -129,6 +129,19 @@ pub struct Instance {
flags: crate::InstanceFlags,
}

impl Instance {
pub unsafe fn create_surface_from_visual(
&self,
visual: *mut dcomp::IDCompositionVisual,
) -> Surface {
Surface {
factory: self.factory,
target: SurfaceTarget::Visual(native::WeakPtr::from_raw(visual)),
swap_chain: None,
}
}
}

unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}

Expand All @@ -144,9 +157,14 @@ struct SwapChain {
size: wgt::Extent3d,
}

enum SurfaceTarget {
WndHandle(windef::HWND),
Visual(native::WeakPtr<dcomp::IDCompositionVisual>),
}

pub struct Surface {
factory: native::WeakPtr<dxgi1_4::IDXGIFactory4>,
wnd_handle: windef::HWND,
target: SurfaceTarget,
swap_chain: Option<SwapChain>,
}

Expand Down Expand Up @@ -617,22 +635,48 @@ impl crate::Surface<Api> for Surface {
};

let hr = {
profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd");
self.factory.CreateSwapChainForHwnd(
device.present_queue.as_mut_ptr() as *mut _,
self.wnd_handle,
&raw_desc,
ptr::null(),
ptr::null_mut(),
swap_chain1.mut_void() as *mut *mut _,
)
match self.target {
SurfaceTarget::WndHandle(wnd_handle) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd");
self.factory.CreateSwapChainForHwnd(
device.present_queue.as_mut_ptr() as *mut _,
wnd_handle,
&raw_desc,
ptr::null(),
ptr::null_mut(),
swap_chain1.mut_void() as *mut *mut _,
)
}
SurfaceTarget::Visual(_) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition");
self.factory.CreateSwapChainForComposition(
device.present_queue.as_mut_ptr() as *mut _,
&raw_desc,
ptr::null_mut(),
swap_chain1.mut_void() as *mut *mut _,
)
}
}
};

if let Err(err) = hr.into_result() {
log::error!("SwapChain creation error: {}", err);
return Err(crate::SurfaceError::Other("swap chain creation"));
}

match self.target {
SurfaceTarget::WndHandle(_) => {}
SurfaceTarget::Visual(visual) => {
if let Err(err) = visual.SetContent(swap_chain1.as_unknown()).into_result()
{
log::error!("Unable to SetContent: {}", err);
return Err(crate::SurfaceError::Other(
"IDCompositionVisual::SetContent",
));
}
}
}

match swap_chain1.cast::<dxgi1_4::IDXGISwapChain3>().into_result() {
Ok(swap_chain3) => {
swap_chain1.destroy();
Expand All @@ -646,13 +690,18 @@ impl crate::Surface<Api> for Surface {
}
};

// Disable automatic Alt+Enter handling by DXGI.
const DXGI_MWA_NO_WINDOW_CHANGES: u32 = 1;
const DXGI_MWA_NO_ALT_ENTER: u32 = 2;
self.factory.MakeWindowAssociation(
self.wnd_handle,
DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER,
);
match self.target {
SurfaceTarget::WndHandle(wnd_handle) => {
// Disable automatic Alt+Enter handling by DXGI.
const DXGI_MWA_NO_WINDOW_CHANGES: u32 = 1;
const DXGI_MWA_NO_ALT_ENTER: u32 = 2;
self.factory.MakeWindowAssociation(
wnd_handle,
DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER,
);
}
SurfaceTarget::Visual(_) => {}
}

swap_chain.SetMaximumFrameLatency(config.swap_chain_size);
let waitable = swap_chain.GetFrameLatencyWaitableObject();
Expand Down
17 changes: 17 additions & 0 deletions wgpu/src/backend/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,23 @@ impl Context {
}
}

#[cfg(target_os = "windows")]
pub unsafe fn create_surface_from_visual(
self: &Arc<Self>,
visual: *mut std::ffi::c_void,
) -> crate::Surface {
let id = self
.0
.instance_create_surface_from_visual(visual, PhantomData);
crate::Surface {
context: Arc::clone(self),
id: Surface {
id,
configured_device: Mutex::default(),
},
}
}

fn handle_error(
&self,
sink_mutex: &Mutex<ErrorSinkRaw>,
Expand Down
10 changes: 10 additions & 0 deletions wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,16 @@ impl Instance {
self.context.create_surface_from_core_animation_layer(layer)
}

/// Creates a surface from `IDCompositionVisual`.
///
/// # Safety
///
/// - visual must be a valid IDCompositionVisual to create a surface upon.
#[cfg(target_os = "windows")]
pub unsafe fn create_surface_from_visual(&self, visual: *mut std::ffi::c_void) -> Surface {
self.context.create_surface_from_visual(visual)
}

/// Creates a surface from a `web_sys::HtmlCanvasElement`.
///
/// # Safety
Expand Down

0 comments on commit 8c35197

Please sign in to comment.