erupt_bootstrap/
instance.rs

1//! Instance creation utils.
2use erupt::{
3    cstr, vk, CustomEntryLoader, ExtendableFrom, InstanceLoader, InstanceLoaderBuilder,
4    LoaderError, SmallVec,
5};
6use std::{
7    ffi::{c_void, CStr, CString, NulError},
8    fmt,
9    os::raw::c_char,
10};
11use thiserror::Error;
12
13/// Require, request or disable validation layers.
14#[derive(Debug, Copy, Clone)]
15pub enum ValidationLayers {
16    /// Instance creation will fail if there are no validation layers installed.
17    Require,
18    /// If there are validation layers installed, enable them.
19    Request,
20    /// Don't enable validation layers.
21    Disable,
22}
23
24/// Enable or disable the debug messenger, optionally providing a custom callback.
25#[derive(Copy, Clone)]
26pub enum DebugMessenger {
27    /// Enables the debug messenger with the [`default_debug_callback`]
28    /// callback.
29    Default,
30    /// Enables the debug messenger with a custom, user-provided callback.
31    Custom {
32        /// The user provided callback function. Feel free to take a look at the
33        /// [`default_debug_callback`] when implementing your own.
34        callback: vk::PFN_vkDebugUtilsMessengerCallbackEXT,
35        /// A user data pointer passed to the debug callback.
36        user_data_pointer: *mut c_void,
37    },
38    /// Disables the debug messenger.
39    Disable,
40}
41
42/// The default debug callback used in [`DebugMessenger::Default`].
43pub unsafe extern "system" fn default_debug_callback(
44    message_severity: vk::DebugUtilsMessageSeverityFlagBitsEXT,
45    message_type: vk::DebugUtilsMessageTypeFlagsEXT,
46    p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT,
47    _p_user_data: *mut c_void,
48) -> vk::Bool32 {
49    let message_severity = format!("{:?}", message_severity);
50    let message_severity = message_severity.strip_suffix("_EXT").unwrap();
51
52    let message_type = format!("{:?}", message_type);
53    let message_type = message_type.strip_suffix("_EXT").unwrap();
54
55    let message = CStr::from_ptr((*p_callback_data).p_message).to_string_lossy();
56    // \x1b[1m{string}\x1b[0m - bold text.
57    eprintln!("\x1b[1m{message_severity}\x1b[0m | \x1b[1m{message_type}\x1b[0m\n{message}");
58
59    vk::FALSE
60}
61
62/// Metadata for after instance creation.
63#[derive(Clone)]
64pub struct InstanceMetadata {
65    instance_handle: vk::Instance,
66    api_version: u32,
67    enabled_layers: SmallVec<CString>,
68    enabled_extensions: SmallVec<CString>,
69}
70
71impl InstanceMetadata {
72    /// The instance this metadata belongs to.
73    #[inline]
74    pub fn instance_handle(&self) -> vk::Instance {
75        self.instance_handle
76    }
77
78    /// Retrieve the used instance API version.
79    #[inline]
80    pub fn api_version_raw(&self) -> u32 {
81        self.api_version
82    }
83
84    /// Retrieve the used instance API major version.
85    #[inline]
86    pub fn api_version_major(&self) -> u32 {
87        vk::api_version_major(self.api_version)
88    }
89
90    /// Retrieve the used instance API minor version.
91    #[inline]
92    pub fn api_version_minor(&self) -> u32 {
93        vk::api_version_minor(self.api_version)
94    }
95
96    /// List of all enabled layers in the instance.
97    #[inline]
98    pub fn enabled_layers(&self) -> &[CString] {
99        &self.enabled_layers
100    }
101
102    /// Returns true if `layer` is enabled.
103    #[inline]
104    pub unsafe fn is_layer_enabled(&self, layer: *const c_char) -> bool {
105        let qry = CStr::from_ptr(layer);
106        self.enabled_layers.iter().any(|e| e.as_c_str() == qry)
107    }
108
109    /// List of all enabled extensions in the instance.
110    #[inline]
111    pub fn enabled_extensions(&self) -> &[CString] {
112        &self.enabled_extensions
113    }
114
115    /// Returns true if `extension` is enabled.
116    #[inline]
117    pub unsafe fn is_extension_enabled(&self, extension: *const c_char) -> bool {
118        let qry = CStr::from_ptr(extension);
119        self.enabled_extensions.iter().any(|i| i.as_c_str() == qry)
120    }
121}
122
123impl fmt::Debug for InstanceMetadata {
124    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
125        fmt.debug_struct("InstanceMetadata")
126            .field(
127                "api_version",
128                &format_args!("{}.{}", self.api_version_major(), self.api_version_minor()),
129            )
130            .field("enabled_layers", &self.enabled_layers)
131            .field("enabled_extensions", &self.enabled_extensions)
132            .finish()
133    }
134}
135
136/// Errors that can occur during instance creation.
137#[derive(Debug, Error)]
138pub enum InstanceCreationError {
139    /// Vulkan Error.
140    #[error("vulkan error")]
141    VulkanError(#[from] vk::Result),
142    /// One or more layers are not present.
143    #[error("layers ({0:?}) not present")]
144    LayersNotPresent(SmallVec<CString>),
145    /// One or more extensions are not present.
146    #[error("extensions ({0:?}) not present")]
147    ExtensionsNotPresent(SmallVec<CString>),
148    /// The instance loader creation failed.
149    #[error("loader creation error")]
150    LoaderCreation(#[from] LoaderError),
151}
152
153/// Allows to easily create an [`erupt::InstanceLoader`] and friends.
154pub struct InstanceBuilder<'a> {
155    loader_builder: InstanceLoaderBuilder<'a>,
156    app_name: Option<CString>,
157    app_version: Option<u32>,
158    engine_name: Option<CString>,
159    engine_version: Option<u32>,
160    required_api_version: u32,
161    requested_api_version: Option<u32>,
162    layers: SmallVec<(*const c_char, bool)>,
163    extensions: SmallVec<(*const c_char, bool)>,
164    debug_messenger: DebugMessenger,
165    debug_message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
166    debug_message_type: vk::DebugUtilsMessageTypeFlagsEXT,
167    enabled_validation_features: SmallVec<vk::ValidationFeatureEnableEXT>,
168    disabled_validation_features: SmallVec<vk::ValidationFeatureDisableEXT>,
169    allocator: Option<vk::AllocationCallbacks>,
170}
171
172impl<'a> InstanceBuilder<'a> {
173    /// Create a new instance builder with opinionated defaults.
174    #[inline]
175    pub fn new() -> Self {
176        InstanceBuilder::with_loader_builder(InstanceLoaderBuilder::new())
177    }
178
179    /// Create a new instance builder with a custom
180    /// [`erupt::InstanceLoaderBuilder`] and opinionated defaults.
181    #[inline]
182    pub fn with_loader_builder(loader_builder: InstanceLoaderBuilder<'a>) -> Self {
183        InstanceBuilder {
184            loader_builder,
185            app_name: None,
186            app_version: None,
187            engine_name: None,
188            engine_version: None,
189            required_api_version: vk::API_VERSION_1_0,
190            requested_api_version: None,
191            layers: SmallVec::new(),
192            extensions: SmallVec::new(),
193            debug_messenger: DebugMessenger::Disable,
194            debug_message_severity: vk::DebugUtilsMessageSeverityFlagsEXT::WARNING_EXT
195                | vk::DebugUtilsMessageSeverityFlagsEXT::ERROR_EXT,
196            debug_message_type: vk::DebugUtilsMessageTypeFlagsEXT::GENERAL_EXT
197                | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION_EXT
198                | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE_EXT,
199            enabled_validation_features: SmallVec::new(),
200            disabled_validation_features: SmallVec::new(),
201            allocator: None,
202        }
203    }
204
205    /// Application name to advertise.
206    #[inline]
207    pub fn app_name(mut self, app_name: &str) -> Result<Self, NulError> {
208        self.app_name = Some(CString::new(app_name)?);
209        Ok(self)
210    }
211
212    /// Application version to advertise.
213    #[inline]
214    pub fn app_version(mut self, major: u32, minor: u32) -> Self {
215        self.app_version = Some(vk::make_api_version(0, major, minor, 0));
216        self
217    }
218
219    /// Application version to advertise.
220    #[inline]
221    pub fn app_version_raw(mut self, app_version: u32) -> Self {
222        self.app_version = Some(app_version);
223        self
224    }
225
226    /// Engine name to advertise.
227    #[inline]
228    pub fn engine_name(mut self, engine_name: &str) -> Result<Self, NulError> {
229        self.engine_name = Some(CString::new(engine_name)?);
230        Ok(self)
231    }
232
233    /// Engine version to advertise.
234    #[inline]
235    pub fn engine_version(mut self, major: u32, minor: u32) -> Self {
236        self.engine_version = Some(vk::make_api_version(0, major, minor, 0));
237        self
238    }
239
240    /// Engine version to advertise.
241    #[inline]
242    pub fn engine_version_raw(mut self, engine_version: u32) -> Self {
243        self.engine_version = Some(engine_version);
244        self
245    }
246
247    /// Instance API version to be used as minimum requirement.
248    #[inline]
249    pub fn require_api_version(mut self, major: u32, minor: u32) -> Self {
250        self.required_api_version = vk::make_api_version(0, major, minor, 0);
251        self
252    }
253
254    /// Instance API version to be used as minimum requirement.
255    #[inline]
256    pub fn require_api_version_raw(mut self, api_version: u32) -> Self {
257        self.required_api_version = api_version;
258        self
259    }
260
261    /// Instance API version to request. If it is not supported, fall back to
262    /// the highest supported version.
263    #[inline]
264    pub fn request_api_version(mut self, major: u32, minor: u32) -> Self {
265        self.requested_api_version = Some(vk::make_api_version(0, major, minor, 0));
266        self
267    }
268
269    /// Instance API version to request. If it is not supported, fall back to
270    /// the highest supported version.
271    #[inline]
272    pub fn request_api_version_raw(mut self, api_version: u32) -> Self {
273        self.requested_api_version = Some(api_version);
274        self
275    }
276
277    /// Try to enable this layer, ignore if it's not supported
278    #[inline]
279    pub fn request_layer(mut self, layer: *const c_char) -> Self {
280        self.layers.push((layer, false));
281        self
282    }
283
284    /// Enable this layer, fail if it's not supported.
285    #[inline]
286    pub fn require_layer(mut self, layer: *const c_char) -> Self {
287        self.layers.push((layer, true));
288        self
289    }
290
291    /// Try to enable this extension, ignore if it is not supported.
292    #[inline]
293    pub fn request_extension(mut self, extension: *const c_char) -> Self {
294        self.extensions.push((extension, false));
295        self
296    }
297
298    /// Enable this extension, fail if it's not supported.
299    #[inline]
300    pub fn require_extension(mut self, extension: *const c_char) -> Self {
301        self.extensions.push((extension, true));
302        self
303    }
304
305    #[cfg(feature = "surface")]
306    /// Adds an requirement on all Vulkan extensions necessary to create a
307    /// surface on `window_handle`. You can also manually add these extensions.
308    /// Returns `None` if the corresponding Vulkan surface extensions couldn't
309    /// be found. This is only supported on feature `surface`.
310    #[inline]
311    pub fn require_surface_extensions(
312        mut self,
313        window_handle: &impl raw_window_handle::HasRawWindowHandle,
314    ) -> Option<Self> {
315        let required_extensions =
316            erupt::utils::surface::enumerate_required_extensions(window_handle).ok()?;
317        self.extensions
318            .extend(required_extensions.into_iter().map(|name| (name, true)));
319        Some(self)
320    }
321
322    /// Add Khronos validation layers.
323    #[inline]
324    pub fn validation_layers(mut self, validation_layers: ValidationLayers) -> Self {
325        match validation_layers {
326            ValidationLayers::Require | ValidationLayers::Request => {
327                self.layers.push((
328                    cstr!("VK_LAYER_KHRONOS_validation"),
329                    matches!(validation_layers, ValidationLayers::Require),
330                ));
331
332                self.extensions
333                    .push((vk::EXT_VALIDATION_FEATURES_EXTENSION_NAME, false));
334            }
335            ValidationLayers::Disable => (),
336        }
337
338        self
339    }
340
341    /// Try to create a debug messenger with the config provided by
342    /// `debug_messenger`.
343    #[inline]
344    pub fn request_debug_messenger(mut self, debug_messenger: DebugMessenger) -> Self {
345        if !matches!(debug_messenger, DebugMessenger::Disable) {
346            self.extensions
347                .push((vk::EXT_DEBUG_UTILS_EXTENSION_NAME, false));
348        }
349
350        self.debug_messenger = debug_messenger;
351        self
352    }
353
354    /// Filter for the severity of debug messages.
355    #[inline]
356    pub fn debug_message_severity(
357        mut self,
358        severity: vk::DebugUtilsMessageSeverityFlagsEXT,
359    ) -> Self {
360        self.debug_message_severity = severity;
361        self
362    }
363
364    /// Filter for the type of debug messages.
365    #[inline]
366    pub fn debug_message_type(mut self, ty: vk::DebugUtilsMessageTypeFlagsEXT) -> Self {
367        self.debug_message_type = ty;
368        self
369    }
370
371    /// Enable an additional feature in the validation layers.
372    #[inline]
373    pub fn enable_validation_feature(
374        mut self,
375        validation_feature: vk::ValidationFeatureEnableEXT,
376    ) -> Self {
377        self.enabled_validation_features.push(validation_feature);
378        self
379    }
380
381    /// Disable an feature in the validation layers.
382    #[inline]
383    pub fn disable_validation_feature(
384        mut self,
385        validation_feature: vk::ValidationFeatureDisableEXT,
386    ) -> Self {
387        self.disabled_validation_features.push(validation_feature);
388        self
389    }
390
391    /// Allocation callback to use for internal Vulkan calls in the builder.
392    #[inline]
393    pub fn allocation_callbacks(mut self, allocator: vk::AllocationCallbacks) -> Self {
394        self.allocator = Some(allocator);
395        self
396    }
397
398    /// Returns the [`erupt::InstanceLoader`], an debug messenger if it was
399    /// requested and successfully created, and [`InstanceMetadata`] about what
400    /// is actually enabled in the instance.
401    pub unsafe fn build<T>(
402        self,
403        entry: &'a CustomEntryLoader<T>,
404    ) -> Result<
405        (
406            InstanceLoader,
407            Option<vk::DebugUtilsMessengerEXT>,
408            InstanceMetadata,
409        ),
410        InstanceCreationError,
411    > {
412        let mut required_api_version = self.required_api_version;
413        let instance_version = entry.instance_version();
414        if let Some(requested_api_version) = self.requested_api_version {
415            required_api_version =
416                required_api_version.max(requested_api_version.min(vk::make_api_version(
417                    0,
418                    vk::api_version_major(instance_version),
419                    vk::api_version_minor(instance_version),
420                    0,
421                )));
422        }
423
424        let mut app_info = vk::ApplicationInfoBuilder::new().api_version(required_api_version);
425
426        let app_name;
427        if let Some(val) = self.app_name {
428            app_name = val;
429            app_info = app_info.application_name(&app_name);
430        }
431
432        if let Some(app_version) = self.app_version {
433            app_info = app_info.application_version(app_version);
434        }
435
436        let engine_name;
437        if let Some(val) = self.engine_name {
438            engine_name = val;
439            app_info = app_info.engine_name(&engine_name);
440        }
441
442        if let Some(engine_version) = self.engine_version {
443            app_info = app_info.engine_version(engine_version);
444        }
445
446        let layer_properties = entry.enumerate_instance_layer_properties(None).result()?;
447        let mut enabled_layers = SmallVec::new();
448        let mut layers_not_present = SmallVec::new();
449        for (layer_name, required) in self.layers {
450            let cstr = CStr::from_ptr(layer_name);
451            let present = layer_properties
452                .iter()
453                .any(|supported_layer| CStr::from_ptr(supported_layer.layer_name.as_ptr()) == cstr);
454
455            match (required, present) {
456                (_, true) => enabled_layers.push(layer_name),
457                (true, false) => layers_not_present.push(cstr.to_owned()),
458                (false, false) => (),
459            }
460        }
461
462        if !layers_not_present.is_empty() {
463            return Err(InstanceCreationError::LayersNotPresent(layers_not_present));
464        }
465
466        let mut extension_properties = entry
467            .enumerate_instance_extension_properties(None, None)
468            .result()?;
469        for &layer_name in &enabled_layers {
470            extension_properties.extend({
471                let layer_name = CStr::from_ptr(layer_name);
472                entry
473                    .enumerate_instance_extension_properties(Some(layer_name), None)
474                    .result()?
475                    .into_iter()
476            });
477        }
478
479        let mut enabled_extensions = SmallVec::new();
480        let mut extensions_not_present = SmallVec::new();
481        let debug_utils_cstr = CStr::from_ptr(vk::EXT_DEBUG_UTILS_EXTENSION_NAME);
482        let mut is_debug_utils_enabled = false;
483        let validation_features_cstr = CStr::from_ptr(vk::EXT_VALIDATION_FEATURES_EXTENSION_NAME);
484        let mut is_validation_features_enabled = false;
485        for (extension_name, required) in self.extensions {
486            let cstr = CStr::from_ptr(extension_name);
487            let present = extension_properties.iter().any(|supported_extension| {
488                CStr::from_ptr(supported_extension.extension_name.as_ptr()) == cstr
489            });
490
491            match (required, present) {
492                (_, true) => {
493                    is_debug_utils_enabled |= cstr == debug_utils_cstr;
494                    is_validation_features_enabled |= cstr == validation_features_cstr;
495                    enabled_extensions.push(extension_name);
496                }
497                (true, false) => extensions_not_present.push(cstr.to_owned()),
498                (false, false) => (),
499            }
500        }
501
502        if !extensions_not_present.is_empty() {
503            return Err(InstanceCreationError::ExtensionsNotPresent(
504                extensions_not_present,
505            ));
506        }
507
508        let mut instance_info = vk::InstanceCreateInfoBuilder::new()
509            .application_info(&app_info)
510            .enabled_layer_names(&enabled_layers)
511            .enabled_extension_names(&enabled_extensions);
512
513        let should_create_debug_messenger = !matches!(
514            (&self.debug_messenger, is_debug_utils_enabled),
515            (DebugMessenger::Disable, _) | (_, false)
516        );
517
518        let messenger_info = should_create_debug_messenger.then(|| {
519            let messenger_info = vk::DebugUtilsMessengerCreateInfoEXTBuilder::new()
520                .message_severity(self.debug_message_severity)
521                .message_type(self.debug_message_type);
522            match self.debug_messenger {
523                DebugMessenger::Default => {
524                    messenger_info.pfn_user_callback(Some(default_debug_callback))
525                }
526                DebugMessenger::Custom {
527                    callback,
528                    user_data_pointer,
529                } => messenger_info
530                    .pfn_user_callback(Some(callback))
531                    .user_data(user_data_pointer),
532                DebugMessenger::Disable => unreachable!(),
533            }
534        });
535
536        let mut instance_messenger_info;
537        if let Some(messenger_info) = messenger_info {
538            instance_messenger_info = *messenger_info;
539            instance_info = instance_info.extend_from(&mut instance_messenger_info);
540        }
541
542        let mut validation_features;
543        if is_validation_features_enabled {
544            validation_features = vk::ValidationFeaturesEXTBuilder::new()
545                .enabled_validation_features(&self.enabled_validation_features)
546                .disabled_validation_features(&self.disabled_validation_features);
547            instance_info = instance_info.extend_from(&mut validation_features);
548        }
549
550        let instance = self.loader_builder.build(entry, &instance_info)?;
551        let debug_utils_messenger = messenger_info
552            .map(|messenger_info| unsafe {
553                instance
554                    .create_debug_utils_messenger_ext(&messenger_info, self.allocator.as_ref())
555                    .result()
556            })
557            .transpose()?;
558        let instance_metadata = InstanceMetadata {
559            instance_handle: instance.handle,
560            api_version: app_info.api_version,
561            enabled_layers: enabled_layers
562                .into_iter()
563                .map(|ptr| unsafe { CStr::from_ptr(ptr).to_owned() })
564                .collect(),
565            enabled_extensions: enabled_extensions
566                .into_iter()
567                .map(|ptr| unsafe { CStr::from_ptr(ptr).to_owned() })
568                .collect(),
569        };
570
571        Ok((instance, debug_utils_messenger, instance_metadata))
572    }
573}
574
575impl<'a> Default for InstanceBuilder<'a> {
576    fn default() -> Self {
577        Self::new()
578    }
579}
580
581#[cfg(test)]
582mod tests {
583    use super::*;
584    use erupt::EntryLoader;
585
586    #[test]
587    fn basic() {
588        let entry = EntryLoader::new().unwrap();
589        let (instance, _debug_messenger, _metadata) =
590            unsafe { InstanceBuilder::new().build(&entry).unwrap() };
591
592        unsafe {
593            instance.destroy_instance(None);
594        }
595    }
596
597    #[test]
598    fn validation_and_messenger() {
599        let entry = EntryLoader::new().unwrap();
600        let (instance, debug_messenger, _metadata) = unsafe {
601            InstanceBuilder::new()
602                .validation_layers(ValidationLayers::Request)
603                .request_debug_messenger(DebugMessenger::Default)
604                .build(&entry)
605                .unwrap()
606        };
607
608        unsafe {
609            if let Some(debug_messenger) = debug_messenger {
610                instance.destroy_debug_utils_messenger_ext(debug_messenger, None);
611            }
612
613            instance.destroy_instance(None);
614        }
615    }
616}