vulkanalia_bootstrap/
instance.rs

1use crate::system_info::{DEBUG_UTILS_EXT_NAME, SystemInfo, VALIDATION_LAYER_NAME};
2use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
3use std::borrow::Cow;
4use std::ffi;
5use std::ffi::c_void;
6use std::fmt::Debug;
7use std::sync::Arc;
8use vulkanalia::vk::{
9    self, EntryV1_1, ExtDebugUtilsExtension, HasBuilder, InstanceV1_0, KhrSurfaceExtension,
10};
11use vulkanalia::vk::{AllocationCallbacks, DebugUtilsMessengerEXT};
12use vulkanalia::{Version, window as vk_window};
13
14pub trait WindowTraits: HasDisplayHandle + HasWindowHandle + Debug {}
15impl<T> WindowTraits for T where T: HasDisplayHandle + HasWindowHandle + Debug {}
16
17unsafe extern "system" fn vulkan_debug_callback(
18    message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
19    message_type: vk::DebugUtilsMessageTypeFlagsEXT,
20    p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT,
21    _user_data: *mut std::os::raw::c_void,
22) -> vk::Bool32 {
23    unsafe {
24        let callback_data = *p_callback_data;
25        let message_id_number = callback_data.message_id_number;
26
27        let message_id_name = if callback_data.message_id_name.is_null() {
28            Cow::from("")
29        } else {
30            ffi::CStr::from_ptr(callback_data.message_id_name).to_string_lossy()
31        };
32
33        let message = if callback_data.message.is_null() {
34            Cow::from("")
35        } else {
36            ffi::CStr::from_ptr(callback_data.message).to_string_lossy()
37        };
38
39        println!(
40            "{message_severity:?}:\n{message_type:?} [{message_id_name} ({message_id_number})] : {message}\n",
41        );
42
43        vk::FALSE
44    }
45}
46
47#[derive(Debug)]
48pub struct DebugUserData(*mut c_void);
49
50impl Default for DebugUserData {
51    fn default() -> Self {
52        Self(std::ptr::null_mut())
53    }
54}
55
56impl DebugUserData {
57    /// Caller must ensure that data pointer points to valid memory.
58    pub unsafe fn new(data: *mut c_void) -> Self {
59        Self(data)
60    }
61}
62
63impl DebugUserData {
64    pub fn into_inner(self) -> *mut c_void {
65        self.0
66    }
67}
68
69#[derive(Debug)]
70pub struct InstanceBuilder {
71    // VkApplicationInfo
72    app_name: String,
73    engine_name: String,
74    application_version: Version,
75    engine_version: Version,
76    minimum_instance_version: Version,
77    required_instance_version: Version,
78
79    // VkInstanceCreateInfo
80    layers: Vec<vk::ExtensionName>,
81    extensions: Vec<vk::ExtensionName>,
82    flags: vk::InstanceCreateFlags,
83
84    // debug callback
85    debug_callback: vk::PFN_vkDebugUtilsMessengerCallbackEXT,
86    debug_message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
87    debug_message_type: vk::DebugUtilsMessageTypeFlagsEXT,
88    debug_user_data: DebugUserData,
89
90    // validation checks
91    disabled_validation_checks: Vec<vk::ValidationCheckEXT>,
92    enabled_validation_features: Vec<vk::ValidationFeatureEnableEXT>,
93    disabled_validation_features: Vec<vk::ValidationFeatureDisableEXT>,
94
95    allocation_callbacks: Option<vk::AllocationCallbacks>,
96
97    request_validation_layers: bool,
98    enable_validation_layers: bool,
99    // TODO: make typesafe
100    use_debug_messenger: bool,
101    headless_context: bool,
102
103    window: Option<Arc<dyn WindowTraits>>,
104}
105
106impl InstanceBuilder {
107    pub fn new(window: Option<Arc<dyn WindowTraits>>) -> Self {
108        Self {
109            app_name: "".to_string(),
110            engine_name: "".to_string(),
111            application_version: Version::new(0, 0, 0),
112            engine_version: Version::new(0, 0, 0),
113            minimum_instance_version: Version::new(0, 0, 0),
114            required_instance_version: Version::new(0, 0, 0),
115            layers: vec![],
116            extensions: vec![],
117            flags: Default::default(),
118            debug_callback: None,
119            debug_message_severity: vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
120                | vk::DebugUtilsMessageSeverityFlagsEXT::ERROR,
121            debug_message_type: vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
122                | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
123                | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
124            debug_user_data: Default::default(),
125            disabled_validation_checks: vec![],
126            enabled_validation_features: vec![],
127            disabled_validation_features: vec![],
128            allocation_callbacks: None,
129            request_validation_layers: false,
130            enable_validation_layers: false,
131            use_debug_messenger: false,
132            headless_context: false,
133            window,
134        }
135    }
136
137    pub fn app_name(mut self, app_name: impl Into<String>) -> Self {
138        self.app_name = app_name.into();
139        self
140    }
141
142    pub fn engine_name(mut self, engine_name: impl Into<String>) -> Self {
143        self.engine_name = engine_name.into();
144        self
145    }
146
147    pub fn app_version(mut self, version: Version) -> Self {
148        self.application_version = version;
149        self
150    }
151
152    pub fn engine_version(mut self, version: Version) -> Self {
153        self.engine_version = version;
154        self
155    }
156
157    pub fn require_api_version(mut self, version: Version) -> Self {
158        self.required_instance_version = version;
159        self
160    }
161
162    pub fn minimum_instance_version(mut self, version: Version) -> Self {
163        self.minimum_instance_version = version;
164        self
165    }
166
167    pub fn enable_layer(mut self, layer: vk::ExtensionName) -> Self {
168        self.layers.push(layer.into());
169        self
170    }
171
172    pub fn enable_extension(mut self, extension: vk::ExtensionName) -> Self {
173        self.extensions.push(extension);
174        self
175    }
176
177    pub fn enable_validation_layers(mut self, enable: bool) -> Self {
178        self.enable_validation_layers = enable;
179        self
180    }
181
182    pub fn request_validation_layers(mut self, request: bool) -> Self {
183        self.request_validation_layers = request;
184        self
185    }
186
187    pub fn use_default_debug_messenger(mut self) -> Self {
188        self.use_debug_messenger = true;
189        self.debug_callback = Some(vulkan_debug_callback);
190        self
191    }
192
193    #[cfg(feature = "enable_tracing")]
194    pub fn use_default_tracing_messenger(mut self) -> Self {
195        self.use_debug_messenger = true;
196        self.debug_callback = Some(crate::tracing::vulkan_tracing_callback);
197        self
198    }
199
200    pub fn set_debug_messenger(
201        mut self,
202        callback: vk::PFN_vkDebugUtilsMessengerCallbackEXT,
203    ) -> Self {
204        self.use_debug_messenger = true;
205        self.debug_callback = callback;
206        self
207    }
208
209    pub fn debug_user_data(mut self, debug_user_data: DebugUserData) -> Self {
210        self.debug_user_data = debug_user_data;
211        self
212    }
213
214    pub fn headless(mut self, headless: bool) -> Self {
215        self.headless_context = headless;
216        self
217    }
218
219    pub fn debug_messenger_severity(
220        mut self,
221        severity: vk::DebugUtilsMessageSeverityFlagsEXT,
222    ) -> Self {
223        self.debug_message_severity = severity;
224        self
225    }
226
227    pub fn add_debug_messenger_severity(
228        mut self,
229        severity: vk::DebugUtilsMessageSeverityFlagsEXT,
230    ) -> Self {
231        self.debug_message_severity |= severity;
232        self
233    }
234
235    pub fn debug_messenger_type(mut self, message_type: vk::DebugUtilsMessageTypeFlagsEXT) -> Self {
236        self.debug_message_type = message_type;
237        self
238    }
239
240    pub fn add_debug_messenger_type(
241        mut self,
242        message_type: vk::DebugUtilsMessageTypeFlagsEXT,
243    ) -> Self {
244        self.debug_message_type |= message_type;
245        self
246    }
247
248    #[cfg_attr(feature = "enable_tracing", tracing::instrument(skip(self)))]
249    pub fn build(self) -> crate::Result<Arc<Instance>> {
250        let system_info = SystemInfo::get_system_info()?;
251
252        let instance_version = {
253            if self.minimum_instance_version > Version::V1_0_0
254                || self.required_instance_version > Version::V1_0_0
255            {
256                let version = unsafe { system_info.entry.enumerate_instance_version() }
257                    .map_or(Version::V1_0_0, Version::from);
258
259                if version < self.minimum_instance_version
260                    || (self.minimum_instance_version == Version::V1_0_0
261                        && version < self.required_instance_version)
262                {
263                    return match self
264                        .required_instance_version
265                        .max(self.minimum_instance_version)
266                        .minor
267                    {
268                        3 => Err(crate::InstanceError::VulkanVersion13Unavailable.into()),
269                        2 => Err(crate::InstanceError::VulkanVersion12Unavailable.into()),
270                        1 => Err(crate::InstanceError::VulkanVersion11Unavailable.into()),
271                        minor => Err(crate::InstanceError::VulkanVersionUnavailable(format!(
272                            "1.{minor}"
273                        ))
274                        .into()),
275                    };
276                } else {
277                    version
278                }
279            } else {
280                Version::V1_0_0
281            }
282        };
283
284        #[cfg(feature = "enable_tracing")]
285        {
286            tracing::info!(
287                "Instance version: {}.{}.{}",
288                instance_version.major,
289                instance_version.minor,
290                instance_version.patch
291            );
292        }
293
294        let api_version = if instance_version < Version::V1_1_0
295            || self.required_instance_version < self.minimum_instance_version
296        {
297            instance_version
298        } else {
299            self.required_instance_version
300                .max(self.minimum_instance_version)
301        };
302        #[cfg(feature = "enable_tracing")]
303        {
304            tracing::info!("api_version: {}", api_version);
305        }
306
307        let app_name = self.app_name;
308        let engine_name = self.engine_name;
309
310        let app_info = vk::ApplicationInfo {
311            application_name: app_name.as_bytes().as_ptr() as _,
312            application_version: self.application_version.into(),
313            engine_name: engine_name.as_bytes().as_ptr() as _,
314            engine_version: self.engine_version.into(),
315            api_version: api_version.into(),
316            ..Default::default()
317        };
318
319        #[cfg(feature = "enable_tracing")]
320        {
321            tracing::info!("Creating vkInstance with application info...");
322            tracing::debug!(
323                r#"
324Application info: {{
325    name: {:?},
326    version: {}.{}.{},
327    engine_name: {:?},
328    engine_version: {}.{}.{},
329    api_version: {}.{}.{},
330}}
331            "#,
332                app_name,
333                self.application_version.major,
334                self.application_version.minor,
335                self.application_version.patch,
336                engine_name,
337                self.engine_version.major,
338                self.engine_version.minor,
339                self.engine_version.patch,
340                api_version.major,
341                api_version.minor,
342                api_version.patch,
343            )
344        }
345
346        let mut enabled_extensions: Vec<vk::ExtensionName> = vec![];
347        let mut enabled_layers: Vec<vk::ExtensionName> = vec![];
348
349        enabled_extensions.extend_from_slice(self.extensions.as_slice());
350
351        if self.debug_callback.is_some()
352            && self.use_debug_messenger
353            && system_info.debug_utils_available
354        {
355            enabled_extensions.push(DEBUG_UTILS_EXT_NAME);
356        }
357
358        let properties2_ext_enabled = api_version < Version::V1_1_0
359            && system_info
360                .is_extension_available(&vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name)?;
361
362        if properties2_ext_enabled {
363            enabled_extensions.push(vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name);
364        }
365
366        #[cfg(feature = "portability")]
367        let portability_enumeration_support =
368            system_info.is_extension_available(&vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name)?;
369        #[cfg(feature = "portability")]
370        if portability_enumeration_support {
371            enabled_extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name);
372        }
373
374        if !self.headless_context {
375            if let Some(window) = self.window.clone() {
376                let surface_extensions: Vec<vk::ExtensionName> =
377                    vk_window::get_required_instance_extensions(window.as_ref())
378                        .into_iter()
379                        .map(|ext| **ext)
380                        .collect();
381
382                if !system_info.are_extensions_available(&surface_extensions)? {
383                    return Err(crate::InstanceError::WindowingExtensionsNotPresent(
384                        surface_extensions,
385                    )
386                    .into());
387                };
388
389                enabled_extensions.extend_from_slice(&surface_extensions);
390            }
391        }
392
393        #[cfg(feature = "enable_tracing")]
394        tracing::trace!(?enabled_extensions);
395
396        let all_extensions_supported = system_info.are_extensions_available(&enabled_extensions)?;
397        if !all_extensions_supported {
398            return Err(
399                crate::InstanceError::RequestedExtensionsNotPresent(enabled_extensions).into(),
400            );
401        };
402
403        enabled_layers.extend_from_slice(&self.layers);
404
405        if self.enable_validation_layers
406            || (self.request_validation_layers && system_info.validation_layers_available)
407        {
408            enabled_layers.push(VALIDATION_LAYER_NAME)
409        };
410
411        let all_layers_supported = system_info.are_layers_available(self.layers)?;
412
413        if !all_layers_supported {
414            return Err(crate::InstanceError::RequestedLayersNotPresent(enabled_layers).into());
415        };
416
417        let instance_create_flags = if cfg!(feature = "portability") {
418            self.flags | vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR
419        } else {
420            self.flags
421        };
422
423        let enabled_extension_ptr = enabled_extensions
424            .iter()
425            .map(|e| e.as_ptr())
426            .collect::<Vec<_>>();
427
428        let enabled_layers_ptr = enabled_layers
429            .iter()
430            .map(|e| e.as_ptr())
431            .collect::<Vec<_>>();
432
433        let mut instance_create_info = vk::InstanceCreateInfo::builder()
434            .flags(instance_create_flags)
435            .application_info(&app_info)
436            .enabled_extension_names(&enabled_extension_ptr)
437            .enabled_layer_names(&enabled_layers_ptr);
438
439        let mut features = vk::ValidationFeaturesEXT::builder()
440            .disabled_validation_features(&self.disabled_validation_features)
441            .enabled_validation_features(&self.enabled_validation_features);
442
443        if !self.enabled_validation_features.is_empty()
444            || !self.disabled_validation_features.is_empty()
445        {
446            instance_create_info = instance_create_info.push_next(&mut features);
447        };
448
449        let mut checks = vk::ValidationFlagsEXT::builder();
450        if !self.disabled_validation_checks.is_empty() {
451            checks = checks.disabled_validation_checks(&self.disabled_validation_checks);
452
453            instance_create_info = instance_create_info.push_next(&mut checks);
454        };
455
456        let instance = unsafe {
457            system_info
458                .entry
459                .create_instance(&instance_create_info, self.allocation_callbacks.as_ref())
460        }
461        .map_err(|_| crate::InstanceError::FailedCreateInstance)?;
462
463        #[cfg(feature = "enable_tracing")]
464        tracing::info!("Created vkInstance");
465
466        let mut debug_messenger = None;
467        let mut debug_user_data = self.debug_user_data.into_inner();
468
469        if self.use_debug_messenger {
470            let messenger_create_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
471                .message_severity(self.debug_message_severity)
472                .message_type(self.debug_message_type)
473                .user_callback(self.debug_callback)
474                .user_data(&mut debug_user_data);
475
476            #[cfg(feature = "enable_tracing")]
477            tracing::trace!(?self.debug_callback, "Using debug messenger");
478
479            let messenger =
480                unsafe { instance.create_debug_utils_messenger_ext(&messenger_create_info, None) }?;
481
482            debug_messenger.replace(messenger);
483        };
484
485        let mut surface = None;
486        if let Some(window) = self.window.clone() {
487            surface = Some(unsafe {
488                vk_window::create_surface(&instance, window.as_ref(), window.as_ref())?
489            });
490            #[cfg(feature = "enable_tracing")]
491            tracing::info!("Created vkSurfaceKhr")
492        };
493
494        Ok(Arc::new(Instance {
495            instance,
496            surface,
497            allocation_callbacks: self.allocation_callbacks,
498            instance_version,
499            api_version,
500            properties2_ext_enabled,
501            debug_messenger,
502            _system_info: system_info,
503        }))
504    }
505}
506
507pub struct Instance {
508    pub(crate) instance: vulkanalia::Instance,
509    pub(crate) allocation_callbacks: Option<AllocationCallbacks>,
510    pub(crate) surface: Option<vk::SurfaceKHR>,
511    pub(crate) instance_version: Version,
512    pub api_version: Version,
513    pub(crate) properties2_ext_enabled: bool,
514    pub(crate) debug_messenger: Option<DebugUtilsMessengerEXT>,
515    _system_info: SystemInfo,
516}
517
518impl Instance {
519    pub fn destroy(&self) {
520        unsafe {
521            if let Some(debug_messenger) = self.debug_messenger {
522                self.instance.destroy_debug_utils_messenger_ext(
523                    debug_messenger,
524                    self.allocation_callbacks.as_ref(),
525                );
526            }
527            if let Some(surface) = self.surface {
528                self.instance
529                    .destroy_surface_khr(surface, self.allocation_callbacks.as_ref());
530            }
531            self.instance
532                .destroy_instance(self.allocation_callbacks.as_ref());
533        }
534    }
535}
536
537impl AsRef<vulkanalia::Instance> for Instance {
538    fn as_ref(&self) -> &vulkanalia::Instance {
539        &self.instance
540    }
541}
542
543#[cfg(test)]
544mod tests {
545
546    #[test]
547    fn compiles() {}
548}