1use crate::ALLOCATION_CALLBACK_NONE;
2use ash::{
3 extensions::{ext, khr},
4 prelude::VkResult,
5 vk::{self, make_api_version},
6 Entry,
7};
8#[cfg(feature = "raw-window-handle-05")]
9use raw_window_handle_05::RawDisplayHandle;
10#[cfg(feature = "raw-window-handle-06")]
11use raw_window_handle_06::RawDisplayHandle;
12use std::{
13 error,
14 ffi::{CStr, CString},
15 fmt,
16 os::raw::c_char,
17 sync::Arc,
18};
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
21pub struct ApiVersion {
22 pub major: u32,
23 pub minor: u32,
24}
25
26impl ApiVersion {
27 pub const fn new(major: u32, minor: u32) -> Self {
28 Self { major, minor }
29 }
30
31 pub const fn as_vk_uint(&self) -> u32 {
32 make_api_version(0, self.major, self.minor, 0)
33 }
34}
35
36pub struct Instance {
37 inner: ash::Instance,
38 max_api_version: ApiVersion,
41
42 entry: Arc<Entry>,
44}
45
46impl Instance {
47 pub fn new_with_display_extensions(
51 entry: Arc<Entry>,
52 max_api_version: ApiVersion,
53 display_handle: RawDisplayHandle,
54 layer_names: Vec<CString>,
55 mut extension_names: Vec<CString>,
56 ) -> Result<Self, InstanceError> {
57 let display_extension_name_cstrs = Self::required_surface_extensions(display_handle)?;
58 let display_extension_names: Vec<CString> = display_extension_name_cstrs
59 .into_iter()
60 .map(|&cstr| cstr.to_owned())
61 .collect();
62
63 extension_names.extend_from_slice(&display_extension_names);
64
65 let unsupported_display_extensions =
66 Self::any_unsupported_extensions(&entry, None, extension_names.clone())
67 .map_err(|e| InstanceError::Creation(e))?;
68 if !unsupported_display_extensions.is_empty() {
69 return Err(InstanceError::ExtensionsNotPresent(
70 unsupported_display_extensions,
71 ));
72 }
73
74 Self::new(entry, max_api_version, layer_names, extension_names)
75 }
76
77 pub fn new(
79 entry: Arc<Entry>,
80 max_api_version: ApiVersion,
81 layer_names: Vec<CString>,
82 extension_names: Vec<CString>,
83 ) -> Result<Self, InstanceError> {
84 let layer_name_ptrs: Vec<*const c_char> =
85 layer_names.iter().map(|cstring| cstring.as_ptr()).collect();
86 let extension_name_ptrs: Vec<*const c_char> = extension_names
87 .iter()
88 .map(|cstring| cstring.as_ptr())
89 .collect();
90
91 let appinfo = vk::ApplicationInfo::builder().api_version(max_api_version.as_vk_uint());
92
93 let create_info = vk::InstanceCreateInfo::builder()
94 .application_info(&appinfo)
95 .enabled_layer_names(&layer_name_ptrs)
96 .enabled_extension_names(&extension_name_ptrs);
97
98 let instance_inner =
99 unsafe { entry.create_instance(&create_info, ALLOCATION_CALLBACK_NONE) }
100 .map_err(|e| InstanceError::Creation(e))?;
101
102 Ok(Self {
103 entry,
104 inner: instance_inner,
105 max_api_version,
106 })
107 }
108
109 pub unsafe fn new_from_create_info(
110 entry: Arc<Entry>,
111 create_info_builder: vk::InstanceCreateInfoBuilder,
112 ) -> Result<Self, InstanceError> {
113 let instance_inner =
114 unsafe { entry.create_instance(&create_info_builder, ALLOCATION_CALLBACK_NONE) }
115 .map_err(|e| InstanceError::Creation(e))?;
116
117 let max_api_version = if create_info_builder.p_application_info != std::ptr::null() {
118 let api_version_combined =
119 unsafe { *create_info_builder.p_application_info }.api_version;
120 ApiVersion {
121 major: vk::api_version_major(api_version_combined),
122 minor: vk::api_version_minor(api_version_combined),
123 }
124 } else {
125 ApiVersion { major: 0, minor: 0 }
126 };
127
128 Ok(Self {
129 inner: instance_inner,
130 max_api_version,
131 entry,
132 })
133 }
134
135 pub fn layer_avilable(entry: &Entry, layer_name: CString) -> VkResult<bool> {
137 let layer_properties = entry.enumerate_instance_layer_properties()?;
138 let is_available = layer_properties.iter().any(|layer_prop| {
139 let installed_layer_name =
140 unsafe { CStr::from_ptr(layer_prop.layer_name.as_ptr()) }.to_owned();
141 installed_layer_name == layer_name
142 });
143 Ok(is_available)
144 }
145
146 pub fn any_unsupported_extensions(
150 entry: &Entry,
151 layer_name: Option<&CStr>,
152 mut extension_names: Vec<CString>,
153 ) -> VkResult<Vec<CString>> {
154 let extension_properties = entry.enumerate_instance_extension_properties(layer_name)?;
155 extension_names.retain(|extension_name| {
156 !Self::extension_name_is_in_properties_list(
157 &extension_properties,
158 extension_name.clone(),
159 )
160 });
161 Ok(extension_names)
162 }
163
164 pub fn supports_extension(
166 entry: &Entry,
167 layer_name: Option<&CStr>,
168 extension_name: CString,
169 ) -> VkResult<bool> {
170 let extension_properties = entry.enumerate_instance_extension_properties(layer_name)?;
171 let is_supported =
172 Self::extension_name_is_in_properties_list(&extension_properties, extension_name);
173 Ok(is_supported)
174 }
175
176 pub fn extension_name_is_in_properties_list(
178 extension_properties: &Vec<vk::ExtensionProperties>,
179 extension_name: CString,
180 ) -> bool {
181 extension_properties.iter().any(|props| {
182 let supported_extension_name =
183 unsafe { CStr::from_ptr(props.extension_name.as_ptr()) }.to_owned();
184 supported_extension_name == extension_name
185 })
186 }
187
188 pub fn physical_device_features_1_0(
190 &self,
191 physical_device_handle: vk::PhysicalDevice,
192 ) -> vk::PhysicalDeviceFeatures {
193 unsafe {
194 self.inner()
195 .get_physical_device_features(physical_device_handle)
196 }
197 }
198
199 pub fn physical_device_features_1_1(
201 &self,
202 physical_device_handle: vk::PhysicalDevice,
203 ) -> Option<vk::PhysicalDeviceVulkan11Features> {
204 if self.max_api_version < ApiVersion::new(1, 1) {
205 return None;
206 }
207
208 let mut features_1_1 = vk::PhysicalDeviceVulkan11Features::default();
209 let mut features = vk::PhysicalDeviceFeatures2::builder().push_next(&mut features_1_1);
210 unsafe {
211 self.inner
212 .get_physical_device_features2(physical_device_handle, &mut features)
213 };
214
215 Some(features_1_1)
216 }
217
218 pub fn physical_device_features_1_2(
220 &self,
221 physical_device_handle: vk::PhysicalDevice,
222 ) -> Option<vk::PhysicalDeviceVulkan12Features> {
223 if self.max_api_version < ApiVersion::new(1, 2) {
224 return None;
225 }
226
227 let mut features_1_2 = vk::PhysicalDeviceVulkan12Features::default();
228 let mut features = vk::PhysicalDeviceFeatures2::builder().push_next(&mut features_1_2);
229 unsafe {
230 self.inner
231 .get_physical_device_features2(physical_device_handle, &mut features)
232 };
233
234 Some(features_1_2)
235 }
236
237 pub fn enumerate_physical_devices(&self) -> VkResult<Vec<vk::PhysicalDevice>> {
238 unsafe { self.inner.enumerate_physical_devices() }
239 }
240
241 pub fn required_surface_extensions(
252 display_handle: RawDisplayHandle,
253 ) -> Result<&'static [&'static CStr], InstanceError> {
254 let extensions = match display_handle {
255 RawDisplayHandle::Windows(_) => &Self::SURFACE_EXTS_WINDOWS,
256 RawDisplayHandle::Wayland(_) => &Self::SURFACE_EXTS_WAYLAND,
257 RawDisplayHandle::Xlib(_) => &Self::SURFACE_EXTS_XLIB,
258 RawDisplayHandle::Xcb(_) => &Self::SURFACE_EXTS_XCB,
259 RawDisplayHandle::Android(_) => &Self::SURFACE_EXTS_ANDROID,
260 RawDisplayHandle::AppKit(_) | RawDisplayHandle::UiKit(_) => &Self::SURFACE_EXTS_METAL,
261 _ => return Err(InstanceError::UnsupportedRawDisplayHandle),
262 };
263
264 Ok(extensions)
265 }
266
267 pub const SURFACE_EXTS_WINDOWS: [&'static CStr; 2] =
268 [khr::Surface::name(), khr::Win32Surface::name()];
269 pub const SURFACE_EXTS_WAYLAND: [&'static CStr; 2] =
270 [khr::Surface::name(), khr::WaylandSurface::name()];
271 pub const SURFACE_EXTS_XLIB: [&'static CStr; 2] =
272 [khr::Surface::name(), khr::XlibSurface::name()];
273 pub const SURFACE_EXTS_XCB: [&'static CStr; 2] =
274 [khr::Surface::name(), khr::XcbSurface::name()];
275 pub const SURFACE_EXTS_ANDROID: [&'static CStr; 2] =
276 [khr::Surface::name(), khr::AndroidSurface::name()];
277 pub const SURFACE_EXTS_METAL: [&'static CStr; 2] =
278 [khr::Surface::name(), ext::MetalSurface::name()];
279
280 #[inline]
285 pub fn inner(&self) -> &ash::Instance {
286 &self.inner
287 }
288
289 #[inline]
290 pub fn max_api_version(&self) -> ApiVersion {
291 self.max_api_version
292 }
293
294 #[inline]
295 pub fn entry(&self) -> &Arc<Entry> {
296 &self.entry
297 }
298}
299
300impl Drop for Instance {
301 fn drop(&mut self) {
302 unsafe {
303 self.inner.destroy_instance(ALLOCATION_CALLBACK_NONE);
304 }
305 }
306}
307
308#[derive(Debug, Clone)]
311pub enum InstanceError {
312 UnsupportedRawDisplayHandle,
313 ExtensionsNotPresent(Vec<CString>),
314 Creation(vk::Result),
315}
316
317impl fmt::Display for InstanceError {
318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319 match self {
320 Self::UnsupportedRawDisplayHandle => {
321 write!(f, "unsupported display handle. could not determine the required surface extensions for this window system")
322 }
323 Self::ExtensionsNotPresent(extension_names) => {
324 write!(
325 f,
326 "the following extensions were reqested but are not present: {:?}",
327 extension_names
328 )
329 }
330 Self::Creation(e) => {
331 write!(f, "failed to create device {}", e)
332 }
333 }
334 }
335}
336
337impl error::Error for InstanceError {
338 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
339 match self {
340 Self::UnsupportedRawDisplayHandle => None,
341 Self::ExtensionsNotPresent(_) => None,
342 Self::Creation(e) => Some(e),
343 }
344 }
345}
346
347#[test]
350fn api_version_ordering() {
351 let ver_1_1 = ApiVersion::new(1, 1);
352 let ver_1_2 = ApiVersion::new(1, 2);
353 assert!(ver_1_1 < ver_1_2);
354}