Skip to content

Commit aee8cd1

Browse files
Lazy-load the dcomp library (#8216)
1 parent 04a3401 commit aee8cd1

File tree

7 files changed

+84
-12
lines changed

7 files changed

+84
-12
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wgpu-hal/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ dx12 = [
136136
"dep:libloading",
137137
"dep:log",
138138
"dep:ordered-float",
139+
"dep:once_cell",
139140
"dep:parking_lot",
140141
"dep:profiling",
141142
"dep:range-alloc",
@@ -258,6 +259,7 @@ windows-core = { workspace = true, optional = true }
258259
bit-set = { workspace = true, optional = true }
259260
range-alloc = { workspace = true, optional = true }
260261
gpu-allocator = { workspace = true, optional = true }
262+
once_cell = { workspace = true, optional = true }
261263
# backend: GLES
262264
glutin_wgl_sys = { workspace = true, optional = true }
263265

wgpu-hal/src/dx12/adapter.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::{
1717
self,
1818
dxgi::{factory::DxgiAdapter, result::HResult},
1919
},
20-
dx12::{shader_compilation, SurfaceTarget},
20+
dx12::{dcomp::DCompLib, shader_compilation, SurfaceTarget},
2121
};
2222

2323
impl Drop for super::Adapter {
@@ -55,6 +55,7 @@ impl super::Adapter {
5555
pub(super) fn expose(
5656
adapter: DxgiAdapter,
5757
library: &Arc<D3D12Lib>,
58+
dcomp_lib: &Arc<DCompLib>,
5859
instance_flags: wgt::InstanceFlags,
5960
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
6061
compiler_container: Arc<shader_compilation::CompilerContainer>,
@@ -559,6 +560,7 @@ impl super::Adapter {
559560
raw: adapter,
560561
device,
561562
library: Arc::clone(library),
563+
dcomp_lib: Arc::clone(dcomp_lib),
562564
private_caps,
563565
presentation_timer,
564566
workarounds,
@@ -726,6 +728,7 @@ impl crate::Adapter for super::Adapter {
726728
memory_hints,
727729
self.private_caps,
728730
&self.library,
731+
&self.dcomp_lib,
729732
self.memory_budget_thresholds,
730733
self.compiler_container.clone(),
731734
self.options.clone(),

wgpu-hal/src/dx12/dcomp.rs

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,65 @@
1+
use alloc::sync::Arc;
2+
use core::{ffi, ptr};
3+
4+
use once_cell::sync::Lazy;
15
use windows::Win32::{Foundation::HWND, Graphics::DirectComposition};
6+
use windows_core::Interface;
7+
8+
use super::DynLib;
9+
10+
// Lazy-loaded DirectComposition library
11+
#[derive(Debug)]
12+
pub(crate) struct DCompLib {
13+
lib: Lazy<Result<DynLib, crate::SurfaceError>>,
14+
}
15+
16+
impl DCompLib {
17+
pub(crate) fn new() -> Self {
18+
Self {
19+
lib: Lazy::new(|| unsafe {
20+
DynLib::new("dcomp.dll").map_err(|err| {
21+
log::error!("Error loading dcomp.dll: {err}");
22+
crate::SurfaceError::Other("Error loading dcomp.dll")
23+
})
24+
}),
25+
}
26+
}
27+
28+
fn get_lib(&self) -> Result<&DynLib, crate::SurfaceError> {
29+
match self.lib.as_ref() {
30+
Ok(lib) => Ok(lib),
31+
Err(err) => Err(err.clone()),
32+
}
33+
}
34+
35+
pub(crate) fn create_device(
36+
&self,
37+
) -> Result<DirectComposition::IDCompositionDevice, crate::SurfaceError> {
38+
let lib = self.get_lib()?;
39+
40+
// Calls windows::Win32::Graphics::DirectComposition::DCompositionCreateDevice2 on dcomp.dll
41+
type Fun = extern "system" fn(
42+
pdxdevice: *mut ffi::c_void,
43+
riid: *const windows_core::GUID,
44+
ppdcompdevice: *mut *mut ffi::c_void,
45+
) -> windows_core::HRESULT;
46+
let func: libloading::Symbol<Fun> =
47+
unsafe { lib.get(c"DCompositionCreateDevice2".to_bytes()) }?;
48+
49+
let mut res: Option<DirectComposition::IDCompositionDevice> = None;
50+
51+
(func)(
52+
ptr::null_mut(),
53+
&DirectComposition::IDCompositionDevice::IID,
54+
<*mut _>::cast(&mut res),
55+
)
56+
.map(|| res.unwrap())
57+
.map_err(|err| {
58+
log::error!("DirectComposition::DCompositionCreateDevice2 failed: {err}");
59+
crate::SurfaceError::Other("DirectComposition::DCompositionCreateDevice2")
60+
})
61+
}
62+
}
263

364
#[derive(Default)]
465
pub struct DCompState {
@@ -10,10 +71,11 @@ impl DCompState {
1071
/// If the device is already initialized, it will return the existing state.
1172
pub unsafe fn get_or_init(
1273
&mut self,
74+
lib: &Arc<DCompLib>,
1375
hwnd: &HWND,
1476
) -> Result<&mut InnerState, crate::SurfaceError> {
1577
if self.inner.is_none() {
16-
self.inner = Some(unsafe { InnerState::init(hwnd) }?);
78+
self.inner = Some(unsafe { InnerState::init(lib, hwnd) }?);
1779
}
1880
Ok(self.inner.as_mut().unwrap())
1981
}
@@ -28,14 +90,9 @@ pub struct InnerState {
2890

2991
impl InnerState {
3092
/// Creates a DirectComposition device and a target for the given window handle.
31-
pub unsafe fn init(hwnd: &HWND) -> Result<Self, crate::SurfaceError> {
93+
pub unsafe fn init(lib: &Arc<DCompLib>, hwnd: &HWND) -> Result<Self, crate::SurfaceError> {
3294
profiling::scope!("DCompState::init");
33-
let dcomp_device: DirectComposition::IDCompositionDevice = {
34-
unsafe { DirectComposition::DCompositionCreateDevice2(None) }.map_err(|err| {
35-
log::error!("DirectComposition::DCompositionCreateDevice failed: {err}");
36-
crate::SurfaceError::Other("DirectComposition::DCompositionCreateDevice")
37-
})?
38-
};
95+
let dcomp_device = lib.create_device()?;
3996

4097
let target = unsafe { dcomp_device.CreateTargetForHwnd(*hwnd, false) }.map_err(|err| {
4198
log::error!("IDCompositionDevice::CreateTargetForHwnd failed: {err}");

wgpu-hal/src/dx12/device.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::{
2626
dxgi::{name::ObjectExt, result::HResult},
2727
},
2828
dx12::{
29-
borrow_optional_interface_temporarily, shader_compilation, suballocation,
29+
borrow_optional_interface_temporarily, shader_compilation, suballocation, DCompLib,
3030
DynamicStorageBufferOffsets, Event, ShaderCacheKey, ShaderCacheValue,
3131
},
3232
AccelerationStructureEntries, TlasInstance,
@@ -46,6 +46,7 @@ impl super::Device {
4646
memory_hints: &wgt::MemoryHints,
4747
private_caps: super::PrivateCapabilities,
4848
library: &Arc<D3D12Lib>,
49+
dcomp_lib: &Arc<DCompLib>,
4950
memory_budget_thresholds: wgt::MemoryBudgetThresholds,
5051
compiler_container: Arc<shader_compilation::CompilerContainer>,
5152
backend_options: wgt::Dx12BackendOptions,
@@ -201,6 +202,7 @@ impl super::Device {
201202
)),
202203
options: backend_options,
203204
library: Arc::clone(library),
205+
dcomp_lib: Arc::clone(dcomp_lib),
204206
#[cfg(feature = "renderdoc")]
205207
render_doc: Default::default(),
206208
null_rtv_handle,

wgpu-hal/src/dx12/instance.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use windows::{
1212
use super::SurfaceTarget;
1313
use crate::{
1414
auxil,
15-
dx12::{shader_compilation::CompilerContainer, D3D12Lib},
15+
dx12::{shader_compilation::CompilerContainer, D3D12Lib, DCompLib},
1616
};
1717

1818
impl crate::Instance for super::Instance {
@@ -104,6 +104,7 @@ impl crate::Instance for super::Instance {
104104
factory,
105105
factory_media,
106106
library: Arc::new(lib_main),
107+
dcomp_lib: Arc::new(DCompLib::new()),
107108
presentation_system: desc.backend_options.dx12.presentation_system,
108109
_lib_dxgi: lib_dxgi,
109110
supports_allow_tearing,
@@ -158,6 +159,7 @@ impl crate::Instance for super::Instance {
158159
super::Adapter::expose(
159160
raw,
160161
&self.library,
162+
&self.dcomp_lib,
161163
self.flags,
162164
self.memory_budget_thresholds,
163165
self.compiler_container.clone(),

wgpu-hal/src/dx12/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ use windows::{
101101
},
102102
};
103103

104+
use self::dcomp::DCompLib;
104105
use crate::auxil::{
105106
self,
106107
dxgi::{
@@ -460,6 +461,7 @@ pub struct Instance {
460461
factory: DxgiFactory,
461462
factory_media: Option<Dxgi::IDXGIFactoryMedia>,
462463
library: Arc<D3D12Lib>,
464+
dcomp_lib: Arc<DCompLib>,
463465
supports_allow_tearing: bool,
464466
presentation_system: wgt::Dx12SwapchainKind,
465467
_lib_dxgi: DxgiLib,
@@ -612,6 +614,7 @@ pub struct Adapter {
612614
raw: DxgiAdapter,
613615
device: Direct3D12::ID3D12Device,
614616
library: Arc<D3D12Lib>,
617+
dcomp_lib: Arc<DCompLib>,
615618
private_caps: PrivateCapabilities,
616619
presentation_timer: auxil::dxgi::time::PresentationTimer,
617620
// Note: this isn't used right now, but we'll need it later.
@@ -685,6 +688,7 @@ pub struct Device {
685688
srv_uav_pool: Mutex<descriptor::CpuPool>,
686689
// library
687690
library: Arc<D3D12Lib>,
691+
dcomp_lib: Arc<DCompLib>,
688692
#[cfg(feature = "renderdoc")]
689693
render_doc: auxil::renderdoc::RenderDoc,
690694
null_rtv_handle: descriptor::Handle,
@@ -1358,7 +1362,8 @@ impl crate::Surface for Surface {
13581362
dcomp_state,
13591363
} => {
13601364
let mut dcomp_state = dcomp_state.lock();
1361-
let dcomp_state = unsafe { dcomp_state.get_or_init(handle) }?;
1365+
let dcomp_state =
1366+
unsafe { dcomp_state.get_or_init(&device.dcomp_lib, handle) }?;
13621367
// Set the new swap chain as the content for the backing visual
13631368
// and commit the changes to the composition visual tree.
13641369
{

0 commit comments

Comments
 (0)