mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Support to create surface from visual on Windows (#2434)
* 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
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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},
|
||||
@@ -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,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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},
|
||||
@@ -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),
|
||||
|
||||
@@ -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 _,
|
||||
};
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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>,
|
||||
}
|
||||
|
||||
@@ -617,15 +635,28 @@ 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() {
|
||||
@@ -633,6 +664,19 @@ impl crate::Surface<Api> for Surface {
|
||||
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();
|
||||
@@ -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();
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user