Skip to content

Commit

Permalink
Add create_surface_from_surface_handle (#3225)
Browse files Browse the repository at this point in the history
Co-authored-by: lixiaopeng.jetspark <[email protected]>
  • Loading branch information
xiaopengli89 and xiaopengli89 authored Jan 19, 2023
1 parent a3e3d25 commit 24a9042
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 6 deletions.
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,34 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
id.0
}

#[cfg(feature = "dx12")]
/// # Safety
///
/// The surface_handle must be valid and able to be used to make a swapchain with.
pub unsafe fn instance_create_surface_from_surface_handle(
&self,
surface_handle: *mut std::ffi::c_void,
id_in: Input<G, SurfaceId>,
) -> SurfaceId {
profiling::scope!("Instance::instance_create_surface_from_surface_handle");

let surface = Surface {
presentation: None,
#[cfg(feature = "vulkan")]
vulkan: None,
dx12: self.instance.dx12.as_ref().map(|inst| HalSurface {
raw: unsafe { inst.create_surface_from_surface_handle(surface_handle) },
}),
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");
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 @@ -93,7 +93,7 @@ libloading = { version = "0.7", optional = true }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["profileapi", "libloaderapi", "windef", "winuser", "dcomp"] }
native = { package = "d3d12", version = "0.5.0", features = ["libloading"], optional = true }
native = { package = "d3d12", version = "0.5.0", git = "https://github.com/gfx-rs/d3d12-rs", rev = "a990c93", features = ["libloading"], optional = true }

[target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies]
mtl = { package = "metal", version = "0.24.0" }
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
None
}
}
SurfaceTarget::Visual(_) => None,
SurfaceTarget::Visual(_) | SurfaceTarget::SurfaceHandle(_) => None,
}
};

Expand Down
17 changes: 17 additions & 0 deletions wgpu-hal/src/dx12/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,21 @@ impl crate::Instance<super::Api> for super::Instance {
desc.flags,
)?;

// Create IDXGIFactoryMedia
let factory_media = match lib_dxgi.create_factory_media() {
Ok(pair) => match pair.into_result() {
Ok(factory_media) => Some(factory_media),
Err(err) => {
log::error!("Failed to create IDXGIFactoryMedia: {}", err);
None
}
},
Err(err) => {
log::info!("IDXGIFactory1 creation function not found: {:?}", err);
None
}
};

let mut supports_allow_tearing = false;
#[allow(trivial_casts)]
if let Some(factory5) = factory.as_factory5() {
Expand All @@ -60,6 +75,7 @@ impl crate::Instance<super::Api> for super::Instance {
Ok(Self {
// The call to create_factory will only succeed if we get a factory4, so this is safe.
factory,
factory_media,
library: Arc::new(lib_main),
_lib_dxgi: lib_dxgi,
supports_allow_tearing,
Expand All @@ -76,6 +92,7 @@ impl crate::Instance<super::Api> for super::Instance {
match window_handle {
raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface {
factory: self.factory,
factory_media: self.factory_media,
target: SurfaceTarget::WndHandle(handle.hwnd as *mut _),
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: None,
Expand Down
34 changes: 32 additions & 2 deletions wgpu-hal/src/dx12/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const ZERO_BUFFER_SIZE: wgt::BufferAddress = 256 << 10;

pub struct Instance {
factory: native::DxgiFactory,
factory_media: Option<native::FactoryMedia>,
library: Arc<native::D3D12Lib>,
supports_allow_tearing: bool,
_lib_dxgi: native::DxgiLib,
Expand All @@ -103,11 +104,25 @@ impl Instance {
) -> Surface {
Surface {
factory: self.factory,
factory_media: self.factory_media,
target: SurfaceTarget::Visual(unsafe { native::WeakPtr::from_raw(visual) }),
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: None,
}
}

pub unsafe fn create_surface_from_surface_handle(
&self,
surface_handle: winnt::HANDLE,
) -> Surface {
Surface {
factory: self.factory,
factory_media: self.factory_media,
target: SurfaceTarget::SurfaceHandle(surface_handle),
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: None,
}
}
}

unsafe impl Send for Instance {}
Expand All @@ -128,10 +143,12 @@ struct SwapChain {
enum SurfaceTarget {
WndHandle(windef::HWND),
Visual(native::WeakPtr<dcomp::IDCompositionVisual>),
SurfaceHandle(winnt::HANDLE),
}

pub struct Surface {
factory: native::DxgiFactory,
factory_media: Option<native::FactoryMedia>,
target: SurfaceTarget,
supports_allow_tearing: bool,
swap_chain: Option<SwapChain>,
Expand Down Expand Up @@ -680,6 +697,19 @@ impl crate::Surface<Api> for Surface {
)
.into_result()
}
SurfaceTarget::SurfaceHandle(handle) => {
profiling::scope!(
"IDXGIFactoryMedia::CreateSwapChainForCompositionSurfaceHandle"
);
self.factory_media
.ok_or(crate::SurfaceError::Other("IDXGIFactoryMedia not found"))?
.create_swapchain_for_composition_surface_handle(
device.present_queue.as_mut_ptr() as *mut _,
handle,
&desc,
)
.into_result()
}
SurfaceTarget::WndHandle(hwnd) => {
profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd");
self.factory
Expand All @@ -703,7 +733,7 @@ impl crate::Surface<Api> for Surface {
};

match self.target {
SurfaceTarget::WndHandle(_) => {}
SurfaceTarget::WndHandle(_) | SurfaceTarget::SurfaceHandle(_) => {}
SurfaceTarget::Visual(visual) => {
if let Err(err) =
unsafe { visual.SetContent(swap_chain1.as_unknown()) }.into_result()
Expand Down Expand Up @@ -741,7 +771,7 @@ impl crate::Surface<Api> for Surface {
)
};
}
SurfaceTarget::Visual(_) => {}
SurfaceTarget::Visual(_) | SurfaceTarget::SurfaceHandle(_) => {}
}

unsafe { swap_chain.SetMaximumFrameLatency(config.swap_chain_size) };
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 @@ -250,6 +250,21 @@ impl Context {
}
}

#[cfg(target_os = "windows")]
pub unsafe fn create_surface_from_surface_handle(
&self,
surface_handle: *mut std::ffi::c_void,
) -> Surface {
let id = unsafe {
self.0
.instance_create_surface_from_surface_handle(surface_handle, ())
};
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 @@ -1517,6 +1517,31 @@ impl Instance {
}
}

/// Creates a surface from `SurfaceHandle`.
///
/// # Safety
///
/// - surface_handle must be a valid SurfaceHandle to create a surface upon.
#[cfg(target_os = "windows")]
pub unsafe fn create_surface_from_surface_handle(
&self,
surface_handle: *mut std::ffi::c_void,
) -> Surface {
let surface = unsafe {
self.context
.as_any()
.downcast_ref::<crate::backend::Context>()
.unwrap()
.create_surface_from_surface_handle(surface_handle)
};
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 24a9042

Please sign in to comment.