1 use hal::adapter::{AdapterInfo, DeviceType};
2
3 use winapi::{
4 shared::{
5 dxgi,
6 dxgi1_2,
7 dxgi1_3,
8 dxgi1_4,
9 dxgi1_5,
10 guiddef::{GUID, REFIID},
11 winerror,
12 },
13 um::unknwnbase::IUnknown,
14 Interface,
15 };
16
17 use wio::com::ComPtr;
18
19 use std::{ffi::OsString, mem, os::windows::ffi::OsStringExt, ptr};
20
21 #[derive(Debug, Copy, Clone)]
22 pub(crate) enum DxgiVersion {
23 /// Capable of the following interfaces:
24 /// * IDXGIObject
25 /// * IDXGIDeviceSubObject
26 /// * IDXGIResource
27 /// * IDXGIKeyedMutex
28 /// * IDXGISurface
29 /// * IDXGISurface1
30 /// * IDXGIOutput
31 /// * IDXGISwapChain
32 /// * IDXGIFactory
33 /// * IDXGIDevice
34 /// * IDXGIFactory1
35 /// * IDXGIAdapter1
36 /// * IDXGIDevice1
37 Dxgi1_0,
38
39 /// Capable of the following interfaces:
40 /// * IDXGIDisplayControl
41 /// * IDXGIOutputDuplication
42 /// * IDXGISurface2
43 /// * IDXGIResource1
44 /// * IDXGIDevice2
45 /// * IDXGISwapChain1
46 /// * IDXGIFactory2
47 /// * IDXGIAdapter2
48 /// * IDXGIOutput1
49 Dxgi1_2,
50
51 /// Capable of the following interfaces:
52 /// * IDXGIDevice3
53 /// * IDXGISwapChain2
54 /// * IDXGIOutput2
55 /// * IDXGIDecodeSwapChain
56 /// * IDXGIFactoryMedia
57 /// * IDXGISwapChainMedia
58 /// * IDXGIOutput3
59 Dxgi1_3,
60
61 /// Capable of the following interfaces:
62 /// * IDXGISwapChain3
63 /// * IDXGIOutput4
64 /// * IDXGIFactory4
65 /// * IDXGIAdapter3
66 Dxgi1_4,
67
68 /// Capable of the following interfaces:
69 /// * IDXGIOutput5
70 /// * IDXGISwapChain4
71 /// * IDXGIDevice4
72 /// * IDXGIFactory5
73 Dxgi1_5,
74 }
75
76 type DxgiFun =
77 unsafe extern "system" fn(REFIID, *mut *mut winapi::ctypes::c_void) -> winerror::HRESULT;
78
create_dxgi_factory1( func: &DxgiFun, guid: &GUID, ) -> Result<ComPtr<dxgi::IDXGIFactory>, winerror::HRESULT>79 fn create_dxgi_factory1(
80 func: &DxgiFun,
81 guid: &GUID,
82 ) -> Result<ComPtr<dxgi::IDXGIFactory>, winerror::HRESULT> {
83 let mut factory: *mut IUnknown = ptr::null_mut();
84
85 let hr = unsafe { func(guid, &mut factory as *mut *mut _ as *mut *mut _) };
86
87 if winerror::SUCCEEDED(hr) {
88 Ok(unsafe { ComPtr::from_raw(factory as *mut _) })
89 } else {
90 Err(hr)
91 }
92 }
93
get_dxgi_factory( ) -> Result<(libloading::Library, ComPtr<dxgi::IDXGIFactory>, DxgiVersion), winerror::HRESULT>94 pub(crate) fn get_dxgi_factory(
95 ) -> Result<(libloading::Library, ComPtr<dxgi::IDXGIFactory>, DxgiVersion), winerror::HRESULT> {
96 // The returned Com-pointer is only safe to use for the lifetime of the Library.
97 let library = libloading::Library::new("dxgi.dll").map_err(|_| -1)?;
98 let func: libloading::Symbol<DxgiFun> =
99 unsafe { library.get(b"CreateDXGIFactory1") }.map_err(|_| -1)?;
100
101 // TODO: do we even need `create_dxgi_factory2`?
102 if let Ok(factory) = create_dxgi_factory1(&func, &dxgi1_5::IDXGIFactory5::uuidof()) {
103 return Ok((library, factory, DxgiVersion::Dxgi1_5));
104 }
105
106 if let Ok(factory) = create_dxgi_factory1(&func, &dxgi1_4::IDXGIFactory4::uuidof()) {
107 return Ok((library, factory, DxgiVersion::Dxgi1_4));
108 }
109
110 if let Ok(factory) = create_dxgi_factory1(&func, &dxgi1_3::IDXGIFactory3::uuidof()) {
111 return Ok((library, factory, DxgiVersion::Dxgi1_3));
112 }
113
114 if let Ok(factory) = create_dxgi_factory1(&func, &dxgi1_2::IDXGIFactory2::uuidof()) {
115 return Ok((library, factory, DxgiVersion::Dxgi1_2));
116 }
117
118 if let Ok(factory) = create_dxgi_factory1(&func, &dxgi::IDXGIFactory1::uuidof()) {
119 return Ok((library, factory, DxgiVersion::Dxgi1_0));
120 }
121
122 // TODO: any reason why above would fail and this wouldnt?
123 match create_dxgi_factory1(&func, &dxgi::IDXGIFactory::uuidof()) {
124 Ok(factory) => Ok((library, factory, DxgiVersion::Dxgi1_0)),
125 Err(hr) => Err(hr),
126 }
127 }
128
enum_adapters1( idx: u32, factory: *mut dxgi::IDXGIFactory, ) -> Result<ComPtr<dxgi::IDXGIAdapter>, winerror::HRESULT>129 fn enum_adapters1(
130 idx: u32,
131 factory: *mut dxgi::IDXGIFactory,
132 ) -> Result<ComPtr<dxgi::IDXGIAdapter>, winerror::HRESULT> {
133 let mut adapter: *mut dxgi::IDXGIAdapter = ptr::null_mut();
134
135 let hr = unsafe {
136 (*(factory as *mut dxgi::IDXGIFactory1))
137 .EnumAdapters1(idx, &mut adapter as *mut *mut _ as *mut *mut _)
138 };
139
140 if winerror::SUCCEEDED(hr) {
141 Ok(unsafe { ComPtr::from_raw(adapter) })
142 } else {
143 Err(hr)
144 }
145 }
146
get_adapter_desc(adapter: *mut dxgi::IDXGIAdapter, version: DxgiVersion) -> AdapterInfo147 fn get_adapter_desc(adapter: *mut dxgi::IDXGIAdapter, version: DxgiVersion) -> AdapterInfo {
148 match version {
149 DxgiVersion::Dxgi1_0 => {
150 let mut desc: dxgi::DXGI_ADAPTER_DESC1 = unsafe { mem::zeroed() };
151 unsafe {
152 (*(adapter as *mut dxgi::IDXGIAdapter1)).GetDesc1(&mut desc);
153 }
154
155 let device_name = {
156 let len = desc.Description.iter().take_while(|&&c| c != 0).count();
157 let name = <OsString as OsStringExt>::from_wide(&desc.Description[.. len]);
158 name.to_string_lossy().into_owned()
159 };
160
161 AdapterInfo {
162 name: device_name,
163 vendor: desc.VendorId as usize,
164 device: desc.DeviceId as usize,
165 device_type: if (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) != 0 {
166 DeviceType::VirtualGpu
167 } else {
168 DeviceType::DiscreteGpu
169 },
170 }
171 }
172 DxgiVersion::Dxgi1_2
173 | DxgiVersion::Dxgi1_3
174 | DxgiVersion::Dxgi1_4
175 | DxgiVersion::Dxgi1_5 => {
176 let mut desc: dxgi1_2::DXGI_ADAPTER_DESC2 = unsafe { mem::zeroed() };
177 unsafe {
178 (*(adapter as *mut dxgi1_2::IDXGIAdapter2)).GetDesc2(&mut desc);
179 }
180
181 let device_name = {
182 let len = desc.Description.iter().take_while(|&&c| c != 0).count();
183 let name = <OsString as OsStringExt>::from_wide(&desc.Description[.. len]);
184 name.to_string_lossy().into_owned()
185 };
186
187 AdapterInfo {
188 name: device_name,
189 vendor: desc.VendorId as usize,
190 device: desc.DeviceId as usize,
191 device_type: if (desc.Flags & dxgi::DXGI_ADAPTER_FLAG_SOFTWARE) != 0 {
192 DeviceType::VirtualGpu
193 } else {
194 DeviceType::DiscreteGpu
195 },
196 }
197 }
198 }
199 }
200
get_adapter( idx: u32, factory: *mut dxgi::IDXGIFactory, version: DxgiVersion, ) -> Result<(ComPtr<dxgi::IDXGIAdapter>, AdapterInfo), winerror::HRESULT>201 pub(crate) fn get_adapter(
202 idx: u32,
203 factory: *mut dxgi::IDXGIFactory,
204 version: DxgiVersion,
205 ) -> Result<(ComPtr<dxgi::IDXGIAdapter>, AdapterInfo), winerror::HRESULT> {
206 let adapter = match version {
207 DxgiVersion::Dxgi1_0
208 | DxgiVersion::Dxgi1_2
209 | DxgiVersion::Dxgi1_3
210 | DxgiVersion::Dxgi1_4
211 | DxgiVersion::Dxgi1_5 => enum_adapters1(idx, factory)?,
212 };
213
214 let desc = get_adapter_desc(adapter.as_raw(), version);
215
216 Ok((adapter, desc))
217 }
218