Skip to content

Add dcomp on windows #7550

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

Open
wants to merge 13 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ Bottom level categories:

### New Features

#### DX12

- Add Dcomp support to DX12 backend. By @n1ght-hunter in [#7550](https://github.com/gfx-rs/wgpu/pull/7550).
```diff
-pub struct Dx12BackendOptions { pub shader_compiler: Dx12Compiler }
+pub struct Dx12BackendOptions { pub shader_compiler: Dx12Compiler, pub use_dcomp: bool }
```

#### Naga

### Bux Fixes
Expand Down
1 change: 1 addition & 0 deletions deno_webgpu/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ impl GPU {
backend_options: wgpu_types::BackendOptions {
dx12: wgpu_types::Dx12BackendOptions {
shader_compiler: wgpu_types::Dx12Compiler::Fxc,
use_dcomp: false,
},
gl: wgpu_types::GlBackendOptions::default(),
noop: wgpu_types::NoopBackendOptions::default(),
Expand Down
1 change: 1 addition & 0 deletions tests/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub fn initialize_instance(backends: wgpu::Backends, params: &TestParameters) ->
backend_options: wgpu::BackendOptions {
dx12: wgpu::Dx12BackendOptions {
shader_compiler: dx12_shader_compiler,
use_dcomp: false,
},
gl: wgpu::GlBackendOptions {
fence_behavior: if cfg!(target_family = "wasm") {
Expand Down
2 changes: 2 additions & 0 deletions wgpu-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ dx12 = [
"windows/Win32_Graphics_Direct3D_Dxc",
"windows/Win32_Graphics_Direct3D",
"windows/Win32_Graphics_Direct3D12",
"windows/Win32_Graphics_Direct3D11",
"windows/Win32_Graphics_Direct3D11on12",
"windows/Win32_Graphics_DirectComposition",
"windows/Win32_Graphics_Dxgi_Common",
"windows/Win32_Security",
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/examples/ray-traced-triangle/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ impl<A: hal::Api> Example<A> {
backend_options: wgpu_types::BackendOptions {
dx12: Dx12BackendOptions {
shader_compiler: wgpu_types::Dx12Compiler::default_dynamic_dxc(),
use_dcomp: false,
},
..Default::default()
},
Expand Down
6 changes: 5 additions & 1 deletion wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,10 @@ impl crate::Adapter for super::Adapter {
) -> Option<crate::SurfaceCapabilities> {
let current_extent = {
match surface.target {
SurfaceTarget::WndHandle(wnd_handle) => {
SurfaceTarget::WndHandle(wnd_handle)
| SurfaceTarget::VisualFromWndHandle {
handle: wnd_handle, ..
} => {
let mut rect = Default::default();
if unsafe { WindowsAndMessaging::GetClientRect(wnd_handle, &mut rect) }.is_ok()
{
Expand Down Expand Up @@ -887,6 +890,7 @@ impl crate::Adapter for super::Adapter {
composite_alpha_modes: match surface.target {
SurfaceTarget::WndHandle(_) => vec![wgt::CompositeAlphaMode::Opaque],
SurfaceTarget::Visual(_)
| SurfaceTarget::VisualFromWndHandle { .. }
| SurfaceTarget::SurfaceHandle(_)
| SurfaceTarget::SwapChainPanel(_) => vec![
wgt::CompositeAlphaMode::Auto,
Expand Down
26 changes: 19 additions & 7 deletions wgpu-hal/src/dx12/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl crate::Instance for super::Instance {
factory,
factory_media,
library: Arc::new(lib_main),
use_dcomp: desc.backend_options.dx12.use_dcomp,
_lib_dxgi: lib_dxgi,
supports_allow_tearing,
flags: desc.flags,
Expand All @@ -121,14 +122,25 @@ impl crate::Instance for super::Instance {
window_handle: raw_window_handle::RawWindowHandle,
) -> Result<super::Surface, crate::InstanceError> {
match window_handle {
raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface {
factory: self.factory.clone(),
factory_media: self.factory_media.clone(),
raw_window_handle::RawWindowHandle::Win32(handle) => {
// https://github.com/rust-windowing/raw-window-handle/issues/171
target: SurfaceTarget::WndHandle(Foundation::HWND(handle.hwnd.get() as *mut _)),
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: RwLock::new(None),
}),
let handle = Foundation::HWND(handle.hwnd.get() as *mut _);
let target = if self.use_dcomp {
SurfaceTarget::VisualFromWndHandle {
handle,
dcomp_state: Default::default(),
}
} else {
SurfaceTarget::WndHandle(handle)
};
Ok(super::Surface {
factory: self.factory.clone(),
factory_media: self.factory_media.clone(),
target,
supports_allow_tearing: self.supports_allow_tearing,
swap_chain: RwLock::new(None),
})
}
_ => Err(crate::InstanceError::new(format!(
"window handle {window_handle:?} is not a Win32 handle"
))),
Expand Down
142 changes: 140 additions & 2 deletions wgpu-hal/src/dx12/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ use windows::{
core::{Free, Interface},
Win32::{
Foundation,
Graphics::{Direct3D, Direct3D12, DirectComposition, Dxgi},
Graphics::{Direct3D, Direct3D11, Direct3D11on12, Direct3D12, DirectComposition, Dxgi},
System::Threading,
},
};
Expand Down Expand Up @@ -458,6 +458,7 @@ pub struct Instance {
factory_media: Option<Dxgi::IDXGIFactoryMedia>,
library: Arc<D3D12Lib>,
supports_allow_tearing: bool,
use_dcomp: bool,
_lib_dxgi: DxgiLib,
flags: wgt::InstanceFlags,
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
Expand Down Expand Up @@ -527,9 +528,21 @@ struct SwapChain {
size: wgt::Extent3d,
}

struct DCompState {
visual: DirectComposition::IDCompositionVisual,
device: DirectComposition::IDCompositionDevice,
// Must be kept alive but is otherwise unused after initialization.
_target: DirectComposition::IDCompositionTarget,
}

enum SurfaceTarget {
/// Borrowed, lifetime externally managed
WndHandle(Foundation::HWND),
/// `handle` is borrowed, lifetime externally managed
VisualFromWndHandle {
handle: Foundation::HWND,
dcomp_state: RwLock<Option<DCompState>>,
},
Visual(DirectComposition::IDCompositionVisual),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be combining these enums?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

honestly i dont know enough about it to say. i think what maybe would make sense is to have a Visual Enum one variant that just has Dcomp Visual and one that has the handle and other state needed

/// Borrowed, lifetime externally managed
SurfaceHandle(Foundation::HANDLE),
Expand Down Expand Up @@ -1228,7 +1241,9 @@ impl crate::Surface for Surface {
Flags: flags.0 as u32,
};
let swap_chain1 = match self.target {
SurfaceTarget::Visual(_) | SurfaceTarget::SwapChainPanel(_) => {
SurfaceTarget::Visual(_)
| SurfaceTarget::VisualFromWndHandle { .. }
| SurfaceTarget::SwapChainPanel(_) => {
profiling::scope!("IDXGIFactory2::CreateSwapChainForComposition");
unsafe {
self.factory.CreateSwapChainForComposition(
Expand Down Expand Up @@ -1275,6 +1290,128 @@ impl crate::Surface for Surface {

match &self.target {
SurfaceTarget::WndHandle(_) | SurfaceTarget::SurfaceHandle(_) => {}
SurfaceTarget::VisualFromWndHandle {
handle,
dcomp_state,
} => {
let mut dcomp_state = dcomp_state.write();
let dcomp_state = match dcomp_state.as_mut() {
Some(s) => s,
None => {
let mut d3d11_device = None;
{
profiling::scope!("Direct3D11on12::D3D11On12CreateDevice");
unsafe {
Direct3D11on12::D3D11On12CreateDevice(
&device.raw,
Direct3D11::D3D11_CREATE_DEVICE_BGRA_SUPPORT.0,
None,
None,
0,
Some(&mut d3d11_device),
None,
None,
)
}
.map_err(|err| {
log::error!(
"Direct3D11on12::D3D11On12CreateDevice failed: {err}"
);
crate::SurfaceError::Other(
"Direct3D11on12::D3D11On12CreateDevice",
)
})?;
}
let d3d11_device = d3d11_device.unwrap();

let dxgi_device = {
profiling::scope!("IDXGIDevice::QueryInterface");
d3d11_device.cast::<Dxgi::IDXGIDevice>().map_err(|err| {
log::error!("IDXGIDevice::QueryInterface failed: {err}");
crate::SurfaceError::Other("IDXGIDevice::QueryInterface")
})?
};

let dcomp_device = {
profiling::scope!(
"DirectComposition::DCompositionCreateDevice"
);
unsafe {
DirectComposition::DCompositionCreateDevice::<
_,
DirectComposition::IDCompositionDevice,
>(&dxgi_device)
}.map_err(|err| {
log::error!(
"DirectComposition::DCompositionCreateDevice failed: {err}"
);
crate::SurfaceError::Other(
"DirectComposition::DCompositionCreateDevice",
)
})?
};

let target = {
profiling::scope!("IDCompositionDevice::CreateTargetForHwnd");
unsafe { dcomp_device.CreateTargetForHwnd(*handle, false)}
.map_err(|err| {
log::error!(
"IDCompositionDevice::CreateTargetForHwnd failed: {err}"
);
crate::SurfaceError::Other(
"IDCompositionDevice::CreateTargetForHwnd",
)
})?
};

let visual = {
profiling::scope!("IDCompositionDevice::CreateVisual");
unsafe { dcomp_device.CreateVisual() }.map_err(|err| {
log::error!(
"IDCompositionDevice::CreateVisual failed: {err}"
);
crate::SurfaceError::Other(
"IDCompositionDevice::CreateVisual",
)
})?
};

{
profiling::scope!("IDCompositionTarget::SetRoot");
unsafe { target.SetRoot(&visual) }.map_err(|err| {
log::error!("IDCompositionTarget::SetRoot failed: {err}");
crate::SurfaceError::Other("IDCompositionTarget::SetRoot")
})?;
}

dcomp_state.insert(DCompState {
visual,
device: dcomp_device,
_target: target,
})
}
};
// Set the new swap chain as the content for the backing visual
// and commit the changes to the composition visual tree.
{
profiling::scope!("IDCompositionVisual::SetContent");
unsafe { dcomp_state.visual.SetContent(&swap_chain1) }.map_err(
|err| {
log::error!("IDCompositionVisual::SetContent failed: {err}");
crate::SurfaceError::Other("IDCompositionVisual::SetContent")
},
)?;
}

// Commit the changes to the composition device.
{
profiling::scope!("IDCompositionDevice::Commit");
unsafe { dcomp_state.device.Commit() }.map_err(|err| {
log::error!("IDCompositionDevice::Commit failed: {err}");
crate::SurfaceError::Other("IDCompositionDevice::Commit")
})?;
}
}
SurfaceTarget::Visual(visual) => {
if let Err(err) = unsafe { visual.SetContent(&swap_chain1) } {
log::error!("Unable to SetContent: {err}");
Expand Down Expand Up @@ -1312,6 +1449,7 @@ impl crate::Surface for Surface {
.into_device_result("MakeWindowAssociation")?;
}
SurfaceTarget::Visual(_)
| SurfaceTarget::VisualFromWndHandle { .. }
| SurfaceTarget::SurfaceHandle(_)
| SurfaceTarget::SwapChainPanel(_) => {}
}
Expand Down
8 changes: 7 additions & 1 deletion wgpu-types/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ impl GlBackendOptions {
pub struct Dx12BackendOptions {
/// Which DX12 shader compiler to use.
pub shader_compiler: Dx12Compiler,
/// Whether to use DirectComposition for managing presentation.
pub use_dcomp: bool,
}

impl Dx12BackendOptions {
Expand All @@ -320,6 +322,7 @@ impl Dx12BackendOptions {
let compiler = Dx12Compiler::from_env().unwrap_or_default();
Self {
shader_compiler: compiler,
use_dcomp: false,
}
}

Expand All @@ -329,7 +332,10 @@ impl Dx12BackendOptions {
#[must_use]
pub fn with_env(self) -> Self {
let shader_compiler = self.shader_compiler.with_env();
Self { shader_compiler }
Self {
shader_compiler,
use_dcomp: false,
}
}
}

Expand Down
Loading