Skip to content

Commit 201d9df

Browse files
committed
Add support for using DirectComposition with DirectX 12.
1 parent ec41864 commit 201d9df

File tree

12 files changed

+151
-15
lines changed

12 files changed

+151
-15
lines changed

deno_webgpu/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ pub fn op_webgpu_request_adapter(
394394
backend_options: wgpu_types::BackendOptions {
395395
dx12: wgpu_types::Dx12BackendOptions {
396396
shader_compiler: wgpu_types::Dx12Compiler::Fxc,
397+
use_dcomp: false,
397398
},
398399
gl: wgpu_types::GlBackendOptions {
399400
gles_minor_version: wgpu_types::Gles3MinorVersion::default(),

examples/src/framework.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ impl<E: Example + wgpu::WasmNotSendSync> From<ExampleTestParams<E>>
551551
height: params.height,
552552
desired_maximum_frame_latency: 2,
553553
present_mode: wgpu::PresentMode::Fifo,
554-
alpha_mode: wgpu::CompositeAlphaMode::Auto,
554+
alpha_mode: wgpu::CompositeAlphaMode::Opaque,
555555
view_formats: vec![format],
556556
},
557557
&ctx.adapter,

tests/src/init.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub fn initialize_instance(backends: wgpu::Backends, force_fxc: bool) -> Instanc
4343
backend_options: wgpu::BackendOptions {
4444
dx12: wgpu::Dx12BackendOptions {
4545
shader_compiler: dx12_shader_compiler,
46+
use_dcomp: false,
4647
},
4748
gl: wgpu::GlBackendOptions { gles_minor_version },
4849
},

wgpu-core/src/instance.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl Instance {
7878
.dx12
7979
.shader_compiler
8080
.clone(),
81+
dx12_use_dcomp: instance_desc.backend_options.dx12.use_dcomp,
8182
gles_minor_version: instance_desc.backend_options.gl.gles_minor_version,
8283
};
8384

wgpu-hal/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ dx12 = [
8282
"windows/Win32_Graphics_Direct3D_Fxc",
8383
"windows/Win32_Graphics_Direct3D_Dxc",
8484
"windows/Win32_Graphics_Direct3D",
85+
"windows/Win32_Graphics_Direct3D11",
86+
"windows/Win32_Graphics_Direct3D11on12",
8587
"windows/Win32_Graphics_Direct3D12",
8688
"windows/Win32_Graphics_DirectComposition",
8789
"windows/Win32_Graphics_Dxgi_Common",

wgpu-hal/examples/halmark/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ impl<A: hal::Api> Example<A> {
9898
flags: wgt::InstanceFlags::from_build_config().with_env(),
9999
// Can't rely on having DXC available, so use FXC instead
100100
dx12_shader_compiler: wgt::Dx12Compiler::Fxc,
101+
dx12_use_dcomp: false,
101102
gles_minor_version: wgt::Gles3MinorVersion::default(),
102103
};
103104
let instance = unsafe { A::Instance::init(&instance_desc)? };

wgpu-hal/examples/ray-traced-triangle/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ impl<A: hal::Api> Example<A> {
243243
dxc_path: "dxcompiler.dll".to_string(),
244244
dxil_path: "dxil.dll".to_string(),
245245
},
246+
dx12_use_dcomp: false,
246247
gles_minor_version: wgt::Gles3MinorVersion::default(),
247248
};
248249
let instance = unsafe { A::Instance::init(&instance_desc)? };

wgpu-hal/src/dx12/adapter.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,10 @@ impl crate::Adapter for super::Adapter {
787787
) -> Option<crate::SurfaceCapabilities> {
788788
let current_extent = {
789789
match surface.target {
790-
SurfaceTarget::WndHandle(wnd_handle) => {
790+
SurfaceTarget::WndHandle(wnd_handle)
791+
| SurfaceTarget::VisualFromWndHandle {
792+
handle: wnd_handle, ..
793+
} => {
791794
let mut rect = Default::default();
792795
if unsafe { WindowsAndMessaging::GetClientRect(wnd_handle, &mut rect) }.is_ok()
793796
{
@@ -831,6 +834,7 @@ impl crate::Adapter for super::Adapter {
831834
composite_alpha_modes: match surface.target {
832835
SurfaceTarget::WndHandle(_) => vec![wgt::CompositeAlphaMode::Opaque],
833836
SurfaceTarget::Visual(_)
837+
| SurfaceTarget::VisualFromWndHandle { .. }
834838
| SurfaceTarget::SurfaceHandle(_)
835839
| SurfaceTarget::SwapChainPanel(_) => vec![
836840
wgt::CompositeAlphaMode::Auto,

wgpu-hal/src/dx12/instance.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ impl crate::Instance for super::Instance {
108108
library: Arc::new(lib_main),
109109
_lib_dxgi: lib_dxgi,
110110
supports_allow_tearing,
111+
use_dcomp: desc.dx12_use_dcomp,
111112
flags: desc.flags,
112113
dxc_container,
113114
})
@@ -119,14 +120,26 @@ impl crate::Instance for super::Instance {
119120
window_handle: raw_window_handle::RawWindowHandle,
120121
) -> Result<super::Surface, crate::InstanceError> {
121122
match window_handle {
122-
raw_window_handle::RawWindowHandle::Win32(handle) => Ok(super::Surface {
123-
factory: self.factory.clone(),
124-
factory_media: self.factory_media.clone(),
123+
raw_window_handle::RawWindowHandle::Win32(handle) => {
125124
// https://github.com/rust-windowing/raw-window-handle/issues/171
126-
target: SurfaceTarget::WndHandle(Foundation::HWND(handle.hwnd.get() as *mut _)),
127-
supports_allow_tearing: self.supports_allow_tearing,
128-
swap_chain: RwLock::new(None),
129-
}),
125+
let handle = Foundation::HWND(handle.hwnd.get() as *mut _);
126+
let target = if self.use_dcomp {
127+
SurfaceTarget::VisualFromWndHandle {
128+
handle,
129+
dcomp_state: Default::default(),
130+
}
131+
} else {
132+
SurfaceTarget::WndHandle(handle)
133+
};
134+
Ok(super::Surface {
135+
factory: self.factory.clone(),
136+
factory_media: self.factory_media.clone(),
137+
138+
target,
139+
supports_allow_tearing: self.supports_allow_tearing,
140+
swap_chain: RwLock::new(None),
141+
})
142+
}
130143
_ => Err(crate::InstanceError::new(format!(
131144
"window handle {window_handle:?} is not a Win32 handle"
132145
))),

wgpu-hal/src/dx12/mod.rs

Lines changed: 110 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use windows::{
5252
core::{Free, Interface},
5353
Win32::{
5454
Foundation,
55-
Graphics::{Direct3D, Direct3D12, DirectComposition, Dxgi},
55+
Graphics::{Direct3D, Direct3D11, Direct3D11on12, Direct3D12, DirectComposition, Dxgi},
5656
System::Threading,
5757
},
5858
};
@@ -410,6 +410,7 @@ pub struct Instance {
410410
factory_media: Option<Dxgi::IDXGIFactoryMedia>,
411411
library: Arc<D3D12Lib>,
412412
supports_allow_tearing: bool,
413+
use_dcomp: bool,
413414
_lib_dxgi: DxgiLib,
414415
flags: wgt::InstanceFlags,
415416
dxc_container: Option<Arc<shader_compilation::DxcContainer>>,
@@ -479,9 +480,21 @@ struct SwapChain {
479480
size: wgt::Extent3d,
480481
}
481482

483+
struct DCompState {
484+
visual: DirectComposition::IDCompositionVisual,
485+
device: DirectComposition::IDCompositionDevice,
486+
// Must be kept alive but is otherwise unused after initialization.
487+
_target: DirectComposition::IDCompositionTarget,
488+
}
489+
482490
enum SurfaceTarget {
483491
/// Borrowed, lifetime externally managed
484492
WndHandle(Foundation::HWND),
493+
/// `handle` is borrowed, lifetime externally managed
494+
VisualFromWndHandle {
495+
handle: Foundation::HWND,
496+
dcomp_state: RwLock<Option<DCompState>>,
497+
},
485498
Visual(DirectComposition::IDCompositionVisual),
486499
/// Borrowed, lifetime externally managed
487500
SurfaceHandle(Foundation::HANDLE),
@@ -1147,6 +1160,61 @@ impl crate::Surface for Surface {
11471160
)
11481161
}
11491162
}
1163+
SurfaceTarget::VisualFromWndHandle {
1164+
handle,
1165+
ref dcomp_state,
1166+
} => unsafe {
1167+
macro_rules! call {
1168+
($name:literal, $e:expr) => {{
1169+
profiling::scope!($name);
1170+
($e).map_err(|_| crate::SurfaceError::Other($name))?
1171+
}};
1172+
}
1173+
1174+
let mut d3d11_device = None;
1175+
call!(
1176+
"Direct3D11on12::D3D11On12CreateDevice",
1177+
Direct3D11on12::D3D11On12CreateDevice(
1178+
&device.raw,
1179+
Direct3D11::D3D11_CREATE_DEVICE_BGRA_SUPPORT.0,
1180+
None,
1181+
None,
1182+
0,
1183+
Some(&mut d3d11_device),
1184+
None,
1185+
None,
1186+
)
1187+
);
1188+
let d3d11_device = d3d11_device.unwrap();
1189+
let dxgi_device: Dxgi::IDXGIDevice =
1190+
call!("IDXGIDevice::QueryInterface", d3d11_device.cast());
1191+
let dcomp_device: DirectComposition::IDCompositionDevice = call!(
1192+
"DirectComposition::DCompositionCreateDevice",
1193+
DirectComposition::DCompositionCreateDevice(&dxgi_device)
1194+
);
1195+
let target = call!(
1196+
"IDCompositionDevice::CreateTargetForHwnd",
1197+
dcomp_device.CreateTargetForHwnd(handle, false)
1198+
);
1199+
let visual = call!(
1200+
"IDCompositionDevice::CreateVisual",
1201+
dcomp_device.CreateVisual()
1202+
);
1203+
call!("IDCompositionTarget::SetRoot", target.SetRoot(&visual));
1204+
1205+
*dcomp_state.write() = Some(DCompState {
1206+
visual,
1207+
device: dcomp_device,
1208+
_target: target,
1209+
});
1210+
1211+
profiling::scope!("IDXGIFactory2::CreateSwapChainForComposition");
1212+
self.factory.CreateSwapChainForComposition(
1213+
&device.present_queue,
1214+
&desc,
1215+
None,
1216+
)
1217+
},
11501218
SurfaceTarget::SurfaceHandle(handle) => {
11511219
profiling::scope!(
11521220
"IDXGIFactoryMedia::CreateSwapChainForCompositionSurfaceHandle"
@@ -1184,6 +1252,17 @@ impl crate::Surface for Surface {
11841252

11851253
match &self.target {
11861254
SurfaceTarget::WndHandle(_) | SurfaceTarget::SurfaceHandle(_) => {}
1255+
SurfaceTarget::VisualFromWndHandle { dcomp_state, .. } => {
1256+
let dcomp_state = dcomp_state.read();
1257+
let dcomp_state = dcomp_state
1258+
.as_ref()
1259+
.expect("dcomp_state was initialized above");
1260+
unsafe {
1261+
dcomp_state.visual.SetContent(&swap_chain1).map_err(|_| {
1262+
crate::SurfaceError::Other("IDCompositionVisual::SetContent")
1263+
})?;
1264+
}
1265+
}
11871266
SurfaceTarget::Visual(visual) => {
11881267
if let Err(err) = unsafe { visual.SetContent(&swap_chain1) } {
11891268
log::error!("Unable to SetContent: {err}");
@@ -1221,6 +1300,7 @@ impl crate::Surface for Surface {
12211300
.into_device_result("MakeWindowAssociation")?;
12221301
}
12231302
SurfaceTarget::Visual(_)
1303+
| SurfaceTarget::VisualFromWndHandle { .. }
12241304
| SurfaceTarget::SurfaceHandle(_)
12251305
| SurfaceTarget::SwapChainPanel(_) => {}
12261306
}
@@ -1349,10 +1429,35 @@ impl crate::Queue for Queue {
13491429
m => unreachable!("Cannot make surface with present mode {m:?}"),
13501430
};
13511431

1352-
profiling::scope!("IDXGISwapchain3::Present");
1353-
unsafe { sc.raw.Present(interval, flags) }
1354-
.ok()
1355-
.into_device_result("Present")?;
1432+
unsafe {
1433+
profiling::scope!("IDXGISwapchain3::Present");
1434+
sc.raw.Present(interval, flags)
1435+
}
1436+
.ok()
1437+
.into_device_result("Present")?;
1438+
1439+
if let SurfaceTarget::VisualFromWndHandle { dcomp_state, .. } = &surface.target {
1440+
let dcomp_state = dcomp_state.read();
1441+
let dcomp_state = dcomp_state.as_ref().unwrap();
1442+
unsafe {
1443+
if dcomp_state
1444+
.device
1445+
.CheckDeviceState()
1446+
.map_err(|_| {
1447+
crate::SurfaceError::Other("IDCompositionDevice::CheckDeviceState")
1448+
})?
1449+
.into()
1450+
{
1451+
profiling::scope!("IDCompositionDevice::Commit");
1452+
dcomp_state
1453+
.device
1454+
.Commit()
1455+
.map_err(|_| crate::SurfaceError::Other("IDCompositionDevice::Commit"))?;
1456+
} else {
1457+
return Err(crate::SurfaceError::Lost);
1458+
}
1459+
}
1460+
}
13561461

13571462
Ok(())
13581463
}

0 commit comments

Comments
 (0)