asche/
instance.rs

1use std::convert::TryInto;
2use std::ffi::CStr;
3use std::fmt::Formatter;
4use std::os::raw::c_char;
5
6use erupt::{vk, ExtendableFromConst, ExtendableFromMut};
7#[cfg(feature = "tracing")]
8use tracing1::{error, info, warn};
9
10use crate::device::Queues;
11#[cfg(debug_assertions)]
12use crate::vk_debug::debug_utils_callback;
13use crate::{AscheError, Device, DeviceConfiguration, Lifetime, Result, Swapchain};
14
15/// Describes how the instance should be configured.
16#[derive(Clone, Debug)]
17pub struct InstanceConfiguration<'a> {
18    /// Name of the application.
19    pub app_name: &'a str,
20    /// Version of the application.
21    pub app_version: Version,
22    /// Name of the engine.
23    pub engine_name: &'a str,
24    /// Version of the engine.
25    pub engine_version: Version,
26    /// Instance extensions to load.
27    pub extensions: Vec<*const c_char>,
28}
29
30/// A version number.
31#[derive(Clone, Debug, Copy, Eq, PartialEq)]
32pub struct Version {
33    /// The version major.
34    pub major: u32,
35    /// The version minor.
36    pub minor: u32,
37    /// The version patch.
38    pub patch: u32,
39}
40
41impl From<Version> for u32 {
42    fn from(v: Version) -> Self {
43        vk::make_api_version(0, v.major, v.minor, v.patch)
44    }
45}
46
47impl std::fmt::Display for Version {
48    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
49        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
50    }
51}
52
53/// Initializes the all Vulkan resources needed to create a device.
54#[derive(Debug)]
55pub struct Instance {
56    pub(crate) surface: vk::SurfaceKHR,
57    #[cfg(debug_assertions)]
58    debug_messenger: vk::DebugUtilsMessengerEXT,
59    raw: erupt::InstanceLoader,
60    _entry: erupt::EntryLoader,
61}
62
63impl Instance {
64    /// Creates a new `Instance`.
65    #[cfg_attr(feature = "profiling", profiling::function)]
66    pub fn new(
67        window_handle: &impl raw_window_handle::HasRawWindowHandle,
68        configuration: InstanceConfiguration,
69    ) -> Result<Instance> {
70        let entry = erupt::EntryLoader::new()?;
71
72        let app_name = std::ffi::CString::new(configuration.app_name.to_owned())?;
73        let engine_name = std::ffi::CString::new(configuration.engine_name.to_owned())?;
74
75        #[cfg(feature = "tracing")]
76        {
77            info!("Application name: {}", configuration.app_name);
78            info!("Application version: {}", configuration.app_version);
79            info!("Engine name: {}", configuration.engine_name);
80            info!("Engine version: {}", configuration.engine_version);
81            info!("Requesting Vulkan API version: 1.2.0");
82        }
83
84        let app_info = vk::ApplicationInfoBuilder::new()
85            .application_name(&app_name)
86            .application_version(configuration.app_version.into())
87            .engine_name(&engine_name)
88            .engine_version(configuration.engine_version.into())
89            .api_version(vk::make_api_version(0, 1, 2, 0));
90
91        // Activate all needed instance layers and extensions.
92        let instance_extensions =
93            unsafe { entry.enumerate_instance_extension_properties(None, None) }.map_err(
94                |err| {
95                    #[cfg(feature = "tracing")]
96                    error!("Unable to enumerate instance extensions: {}", err);
97                    AscheError::VkResult(err)
98                },
99            )?;
100
101        let instance_layers =
102            unsafe { entry.enumerate_instance_layer_properties(None) }.map_err(|err| {
103                #[cfg(feature = "tracing")]
104                error!("Unable to enumerate instance layers: {}", err);
105                AscheError::VkResult(err)
106            })?;
107
108        let extensions =
109            Self::create_instance_extensions(&configuration, &instance_extensions, window_handle)?;
110        let layers = Self::create_layers(&instance_layers);
111        let instance = Self::create_instance(&entry, &app_info, &extensions, &layers)?;
112        let surface =
113            unsafe { erupt::utils::surface::create_surface(&instance, window_handle, None) }
114                .map_err(|err| {
115                    #[cfg(feature = "tracing")]
116                    error!("Unable to create a surface: {}", err);
117                    AscheError::VkResult(err)
118                })?;
119
120        #[cfg(debug_assertions)]
121        let debug_messenger = Self::create_debug_utils(&instance, instance_extensions)?;
122
123        Ok(Self {
124            _entry: entry,
125            raw: instance,
126            surface,
127            #[cfg(debug_assertions)]
128            debug_messenger,
129        })
130    }
131
132    /// The raw Vulkan instance handle.
133    #[inline]
134    pub(crate) fn raw(&self) -> &erupt::InstanceLoader {
135        &self.raw
136    }
137
138    /// Requests a new Vulkan device. Returns a device, a swapchain and the queues created.
139    #[cfg_attr(feature = "profiling", profiling::function)]
140    pub unsafe fn request_device<LT: Lifetime>(
141        self,
142        device_configuration: DeviceConfiguration,
143    ) -> Result<(Device<LT>, Swapchain, Queues)> {
144        Device::new(self, device_configuration)
145    }
146
147    #[cfg(debug_assertions)]
148    fn create_debug_utils(
149        instance: &erupt::InstanceLoader,
150        instance_extensions: Vec<vk::ExtensionProperties>,
151    ) -> Result<vk::DebugUtilsMessengerEXT> {
152        let debug_name = unsafe { CStr::from_ptr(vk::EXT_DEBUG_UTILS_EXTENSION_NAME) };
153        let debug_utils_found = instance_extensions
154            .iter()
155            .any(|props| unsafe { CStr::from_ptr(props.extension_name.as_ptr()) } == debug_name);
156
157        if debug_utils_found {
158            let info = vk::DebugUtilsMessengerCreateInfoEXTBuilder::new()
159                .message_severity(Self::vulkan_log_level())
160                .message_type(vk::DebugUtilsMessageTypeFlagsEXT::all())
161                .pfn_user_callback(Some(debug_utils_callback));
162
163            let utils = unsafe { instance.create_debug_utils_messenger_ext(&info, None) }.map_err(
164                |err| {
165                    #[cfg(feature = "tracing")]
166                    error!("Unable to create the debug utils messenger: {}", err);
167                    AscheError::VkResult(err)
168                },
169            )?;
170            Ok(utils)
171        } else {
172            Err(AscheError::DebugUtilsMissing)
173        }
174    }
175
176    #[cfg(debug_assertions)]
177    fn vulkan_log_level() -> vk::DebugUtilsMessageSeverityFlagsEXT {
178        #[cfg(feature = "tracing")]
179        {
180            use tracing1::level_filters::LevelFilter;
181            match tracing1::level_filters::STATIC_MAX_LEVEL {
182                LevelFilter::OFF => vk::DebugUtilsMessageSeverityFlagsEXT::empty(),
183                LevelFilter::ERROR => vk::DebugUtilsMessageSeverityFlagsEXT::ERROR_EXT,
184                LevelFilter::WARN => {
185                    vk::DebugUtilsMessageSeverityFlagsEXT::ERROR_EXT
186                        | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING_EXT
187                }
188                LevelFilter::INFO => {
189                    vk::DebugUtilsMessageSeverityFlagsEXT::ERROR_EXT
190                        | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING_EXT
191                        | vk::DebugUtilsMessageSeverityFlagsEXT::INFO_EXT
192                }
193                LevelFilter::DEBUG => {
194                    vk::DebugUtilsMessageSeverityFlagsEXT::ERROR_EXT
195                        | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING_EXT
196                        | vk::DebugUtilsMessageSeverityFlagsEXT::INFO_EXT
197                        | vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE_EXT
198                }
199                LevelFilter::TRACE => vk::DebugUtilsMessageSeverityFlagsEXT::all(),
200            }
201        }
202        #[cfg(not(feature = "tracing"))]
203        {
204            vk::DebugUtilsMessageSeverityFlagsEXT::WARNING_EXT
205        }
206    }
207
208    fn create_instance(
209        entry: &erupt::EntryLoader,
210        app_info: &vk::ApplicationInfoBuilder,
211        instance_extensions: &[*const c_char],
212        layers: &[*const c_char],
213    ) -> Result<erupt::InstanceLoader> {
214        #[cfg(feature = "tracing")]
215        Self::print_extensions("instance", instance_extensions)?;
216
217        let create_info = vk::InstanceCreateInfoBuilder::new()
218            .flags(vk::InstanceCreateFlags::empty())
219            .application_info(app_info)
220            .enabled_layer_names(layers)
221            .enabled_extension_names(instance_extensions);
222
223        unsafe { erupt::InstanceLoader::new(entry, &create_info, None) }.map_err(|err| {
224            #[cfg(feature = "tracing")]
225            error!("Unable to create Vulkan instance: {}", err);
226            AscheError::LoaderError(err)
227        })
228    }
229
230    fn create_layers(instance_layers: &[vk::LayerProperties]) -> Vec<*const c_char> {
231        let mut layers = Vec::new();
232
233        layers.retain(|layer| {
234            let instance_layer = unsafe { CStr::from_ptr(*layer) };
235            let found = instance_layers.iter().any(|inst_layer| unsafe {
236                CStr::from_ptr(inst_layer.layer_name.as_ptr()) == instance_layer
237            });
238            if found {
239                true
240            } else {
241                #[cfg(feature = "tracing")]
242                warn!("Unable to find layer: {}", instance_layer.to_string_lossy());
243                false
244            }
245        });
246        layers
247    }
248
249    fn create_instance_extensions(
250        configuration: &InstanceConfiguration,
251        instance_extensions: &[vk::ExtensionProperties],
252        window_handle: &impl raw_window_handle::HasRawWindowHandle,
253    ) -> Result<Vec<*const c_char>> {
254        let mut extensions: Vec<*const c_char> = configuration.extensions.clone();
255
256        let required_extensions =
257            erupt::utils::surface::enumerate_required_extensions(window_handle).map_err(|err| {
258                #[cfg(feature = "tracing")]
259                error!(
260                    "Unable to enumerate the required extensions for the surface creation: {}",
261                    err
262                );
263                AscheError::VkResult(err)
264            })?;
265        extensions.extend(required_extensions.iter());
266
267        #[cfg(debug_assertions)]
268        extensions.push(vk::EXT_DEBUG_UTILS_EXTENSION_NAME);
269
270        // Only keep available extensions.
271        Instance::retain_extensions(instance_extensions, &mut extensions);
272
273        Ok(extensions)
274    }
275
276    fn retain_extensions(
277        present_extensions: &[vk::ExtensionProperties],
278        requested_extensions: &mut Vec<*const i8>,
279    ) {
280        requested_extensions.retain(|ext| {
281            let extension = unsafe { CStr::from_ptr(*ext) };
282            present_extensions.iter().any(|inst_ext| unsafe {
283                CStr::from_ptr(inst_ext.extension_name.as_ptr()) == extension
284            })
285        });
286    }
287
288    pub(crate) fn find_physical_device(
289        &self,
290        device_type: vk::PhysicalDeviceType,
291    ) -> Result<(
292        vk::PhysicalDevice,
293        vk::PhysicalDeviceProperties,
294        vk::PhysicalDeviceDriverProperties,
295    )> {
296        let physical_devices =
297            unsafe { self.raw.enumerate_physical_devices(None) }.map_err(|err| {
298                #[cfg(feature = "tracing")]
299                error!("Unable to enumerate the physical devices: {}", err);
300                AscheError::VkResult(err)
301            })?;
302
303        // We try to find our preferred device type.
304        let mut chosen = self.find_physical_device_inner_loop(device_type, &physical_devices);
305
306        // We try to fall back to the next best thing.
307        if chosen.is_none() {
308            if device_type == vk::PhysicalDeviceType::DISCRETE_GPU {
309                chosen = self.find_physical_device_inner_loop(
310                    vk::PhysicalDeviceType::INTEGRATED_GPU,
311                    &physical_devices,
312                );
313            }
314            if device_type == vk::PhysicalDeviceType::INTEGRATED_GPU {
315                chosen = self.find_physical_device_inner_loop(
316                    vk::PhysicalDeviceType::DISCRETE_GPU,
317                    &physical_devices,
318                );
319            }
320        }
321
322        let chosen = chosen.ok_or(AscheError::RequestDeviceError)?;
323
324        Ok(chosen)
325    }
326
327    fn find_physical_device_inner_loop(
328        &self,
329        device_type: vk::PhysicalDeviceType,
330        physical_devices: &[vk::PhysicalDevice],
331    ) -> Option<(
332        vk::PhysicalDevice,
333        vk::PhysicalDeviceProperties,
334        vk::PhysicalDeviceDriverProperties,
335    )> {
336        let mut chosen = None;
337        for device in physical_devices {
338            let mut physical_device_driver_properties =
339                vk::PhysicalDeviceDriverProperties::default();
340            let physical_device_properties = vk::PhysicalDeviceProperties2Builder::new()
341                .extend_from(&mut physical_device_driver_properties);
342
343            let physical_device_properties = unsafe {
344                self.raw.get_physical_device_properties2(
345                    *device,
346                    Some(physical_device_properties.build()),
347                )
348            };
349
350            if physical_device_properties.properties.device_type == device_type {
351                chosen = Some((
352                    *device,
353                    physical_device_properties.properties,
354                    physical_device_driver_properties,
355                ))
356            }
357        }
358        chosen
359    }
360
361    /// Creates a new logical device. Returns the logical device, and the queue families and the Vulkan queues.
362    /// We have three queue vectors in the following order:
363    ///  * Compute queues
364    ///  * Graphics queues
365    ///  * Transfer queues
366    ///
367    /// The compute and graphics queues use dedicated queue families if provided by the implementation.
368    /// The graphics queues are guaranteed to be able to write the the surface.
369    pub(crate) fn create_device(
370        &self,
371        physical_device: vk::PhysicalDevice,
372        configuration: DeviceConfiguration,
373    ) -> Result<(erupt::DeviceLoader, [u32; 3], [Vec<vk::Queue>; 3])> {
374        let queue_family_properties = unsafe {
375            self.raw
376                .get_physical_device_queue_family_properties(physical_device, None)
377        };
378
379        let graphics_queue_family_id = self.find_queue_family(
380            physical_device,
381            vk::QueueFlags::GRAPHICS,
382            &queue_family_properties,
383        )?;
384        let transfer_queue_family_id = self.find_queue_family(
385            physical_device,
386            vk::QueueFlags::TRANSFER,
387            &queue_family_properties,
388        )?;
389        let compute_queue_family_id = self.find_queue_family(
390            physical_device,
391            vk::QueueFlags::COMPUTE,
392            &queue_family_properties,
393        )?;
394
395        self.create_device_and_queues(
396            physical_device,
397            configuration,
398            graphics_queue_family_id,
399            transfer_queue_family_id,
400            compute_queue_family_id,
401        )
402    }
403
404    #[allow(clippy::as_conversions)]
405    fn create_device_and_queues(
406        &self,
407        physical_device: vk::PhysicalDevice,
408        configuration: DeviceConfiguration,
409        graphics_queue_family_id: u32,
410        transfer_queue_family_id: u32,
411        compute_queue_family_id: u32,
412    ) -> Result<(erupt::DeviceLoader, [u32; 3], [Vec<vk::Queue>; 3])> {
413        let queue_configuration = &configuration.queue_configuration;
414
415        let graphics_count = queue_configuration.graphics_queues.len();
416        let transfer_count = queue_configuration.transfer_queues.len();
417        let compute_count = queue_configuration.compute_queues.len();
418
419        if graphics_count + transfer_count + compute_count == 0 {
420            return Err(AscheError::NoQueueConfigured);
421        }
422
423        if graphics_count > 64 {
424            return Err(AscheError::QueueCountTooHigh(graphics_count));
425        }
426
427        if transfer_count > 64 {
428            return Err(AscheError::QueueCountTooHigh(transfer_count));
429        }
430
431        if compute_count > 64 {
432            return Err(AscheError::QueueCountTooHigh(compute_count));
433        }
434
435        // If some queue families point to the same ID, we need to create only one
436        // `vk::DeviceQueueCreateInfo` for them.
437        if graphics_queue_family_id == transfer_queue_family_id
438            && transfer_queue_family_id != compute_queue_family_id
439        {
440            // Case: G=T,C
441            let mut p1 = Vec::with_capacity(graphics_count + transfer_count);
442            p1.extend_from_slice(&queue_configuration.graphics_queues);
443            p1.extend_from_slice(&queue_configuration.transfer_queues);
444
445            let mut p2 = Vec::with_capacity(compute_count);
446            p2.extend_from_slice(&queue_configuration.compute_queues);
447
448            let mut queue_infos = Vec::with_capacity(2);
449            if !p1.is_empty() {
450                queue_infos.push(
451                    vk::DeviceQueueCreateInfoBuilder::new()
452                        .queue_family_index(graphics_queue_family_id)
453                        .queue_priorities(&p1),
454                );
455            }
456
457            if !p2.is_empty() {
458                queue_infos.push(
459                    vk::DeviceQueueCreateInfoBuilder::new()
460                        .queue_family_index(compute_queue_family_id)
461                        .queue_priorities(&p2),
462                );
463            }
464
465            let device =
466                self.create_logical_device(physical_device, configuration, &queue_infos)?;
467
468            let g_q = (0..graphics_count)
469                .map(|i| unsafe { device.get_device_queue(graphics_queue_family_id, i as u32) })
470                .collect::<_>();
471
472            let t_q = (graphics_count..graphics_count + transfer_count)
473                .map(|i| unsafe { device.get_device_queue(graphics_queue_family_id, i as u32) })
474                .collect::<_>();
475
476            let c_q = (0..compute_count)
477                .map(|i| unsafe { device.get_device_queue(compute_queue_family_id, i as u32) })
478                .collect::<_>();
479
480            Ok((
481                device,
482                [
483                    compute_queue_family_id,
484                    graphics_queue_family_id,
485                    transfer_queue_family_id,
486                ],
487                [c_q, g_q, t_q],
488            ))
489        } else if graphics_queue_family_id != transfer_queue_family_id
490            && transfer_queue_family_id == compute_queue_family_id
491        {
492            // Case: G,T=C
493            let mut p1 = Vec::with_capacity(graphics_count);
494            p1.extend_from_slice(&queue_configuration.graphics_queues);
495
496            let mut p2 = Vec::with_capacity(transfer_count + compute_count);
497            p2.extend_from_slice(&queue_configuration.transfer_queues);
498            p2.extend_from_slice(&queue_configuration.compute_queues);
499
500            let mut queue_infos = Vec::with_capacity(2);
501            if !p1.is_empty() {
502                queue_infos.push(
503                    vk::DeviceQueueCreateInfoBuilder::new()
504                        .queue_family_index(graphics_queue_family_id)
505                        .queue_priorities(&p1),
506                );
507            }
508            if !p2.is_empty() {
509                queue_infos.push(
510                    vk::DeviceQueueCreateInfoBuilder::new()
511                        .queue_family_index(transfer_queue_family_id)
512                        .queue_priorities(&p2),
513                );
514            }
515
516            let device =
517                self.create_logical_device(physical_device, configuration, &queue_infos)?;
518            let g_q = (0..graphics_count)
519                .map(|i| unsafe { device.get_device_queue(graphics_queue_family_id, i as u32) })
520                .collect::<_>();
521
522            let t_q = (0..transfer_count)
523                .map(|i| unsafe { device.get_device_queue(transfer_queue_family_id, i as u32) })
524                .collect::<_>();
525
526            let c_q = (transfer_count..transfer_count + compute_count)
527                .map(|i| unsafe { device.get_device_queue(transfer_queue_family_id, i as u32) })
528                .collect::<_>();
529
530            Ok((
531                device,
532                [
533                    compute_queue_family_id,
534                    graphics_queue_family_id,
535                    transfer_queue_family_id,
536                ],
537                [c_q, g_q, t_q],
538            ))
539        } else if graphics_queue_family_id == compute_queue_family_id
540            && graphics_queue_family_id != transfer_queue_family_id
541        {
542            // Case: G=C,T
543            let mut p1 = Vec::with_capacity(graphics_count + compute_count);
544            p1.extend_from_slice(&queue_configuration.graphics_queues);
545            p1.extend_from_slice(&queue_configuration.compute_queues);
546
547            let mut p2 = Vec::with_capacity(transfer_count);
548            p2.extend_from_slice(&queue_configuration.transfer_queues);
549
550            let mut queue_infos = Vec::with_capacity(2);
551            if !p1.is_empty() {
552                queue_infos.push(
553                    vk::DeviceQueueCreateInfoBuilder::new()
554                        .queue_family_index(graphics_queue_family_id)
555                        .queue_priorities(&p1),
556                );
557            }
558            if !p2.is_empty() {
559                queue_infos.push(
560                    vk::DeviceQueueCreateInfoBuilder::new()
561                        .queue_family_index(transfer_queue_family_id)
562                        .queue_priorities(&p2),
563                );
564            }
565
566            let device =
567                self.create_logical_device(physical_device, configuration, &queue_infos)?;
568
569            let g_q = (0..graphics_count)
570                .map(|i| unsafe { device.get_device_queue(graphics_queue_family_id, i as u32) })
571                .collect::<_>();
572
573            let c_q = (graphics_count..graphics_count + compute_count)
574                .map(|i| unsafe { device.get_device_queue(graphics_queue_family_id, i as u32) })
575                .collect::<_>();
576
577            let t_q = (0..transfer_count)
578                .map(|i| unsafe { device.get_device_queue(transfer_queue_family_id, i as u32) })
579                .collect::<_>();
580
581            Ok((
582                device,
583                [
584                    compute_queue_family_id,
585                    graphics_queue_family_id,
586                    transfer_queue_family_id,
587                ],
588                [c_q, g_q, t_q],
589            ))
590        } else if graphics_queue_family_id == transfer_queue_family_id
591            && transfer_queue_family_id == compute_queue_family_id
592        {
593            // Case: G=T=C
594            let mut p1 = Vec::with_capacity(graphics_count + transfer_count + compute_count);
595            p1.extend_from_slice(&queue_configuration.graphics_queues);
596            p1.extend_from_slice(&queue_configuration.transfer_queues);
597            p1.extend_from_slice(&queue_configuration.compute_queues);
598
599            let queue_infos = [vk::DeviceQueueCreateInfoBuilder::new()
600                .queue_family_index(graphics_queue_family_id)
601                .queue_priorities(&p1)];
602            let device =
603                self.create_logical_device(physical_device, configuration, &queue_infos)?;
604            let g_q = (0..graphics_count)
605                .map(|i| unsafe { device.get_device_queue(graphics_queue_family_id, i as u32) })
606                .collect::<_>();
607
608            let t_q = (graphics_count..graphics_count + transfer_count)
609                .map(|i| unsafe { device.get_device_queue(graphics_queue_family_id, i as u32) })
610                .collect::<_>();
611
612            let c_q = (graphics_count + transfer_count
613                ..graphics_count + transfer_count + compute_count)
614                .map(|i| unsafe { device.get_device_queue(graphics_queue_family_id, i as u32) })
615                .collect::<_>();
616
617            Ok((
618                device,
619                [
620                    compute_queue_family_id,
621                    graphics_queue_family_id,
622                    transfer_queue_family_id,
623                ],
624                [c_q, g_q, t_q],
625            ))
626        } else {
627            // Case: G,T,C
628            let mut p1 = Vec::with_capacity(graphics_count);
629            p1.extend_from_slice(&queue_configuration.graphics_queues);
630
631            let mut p2 = Vec::with_capacity(transfer_count);
632            p2.extend_from_slice(&queue_configuration.transfer_queues);
633
634            let mut p3 = Vec::with_capacity(compute_count);
635            p3.extend_from_slice(&queue_configuration.compute_queues);
636
637            let mut queue_infos = Vec::with_capacity(2);
638            if !p1.is_empty() {
639                queue_infos.push(
640                    vk::DeviceQueueCreateInfoBuilder::new()
641                        .queue_family_index(graphics_queue_family_id)
642                        .queue_priorities(&p1),
643                );
644            }
645            if !p2.is_empty() {
646                queue_infos.push(
647                    vk::DeviceQueueCreateInfoBuilder::new()
648                        .queue_family_index(transfer_queue_family_id)
649                        .queue_priorities(&p2),
650                );
651            }
652            if !p3.is_empty() {
653                queue_infos.push(
654                    vk::DeviceQueueCreateInfoBuilder::new()
655                        .queue_family_index(compute_queue_family_id)
656                        .queue_priorities(&p3),
657                );
658            }
659
660            let device =
661                self.create_logical_device(physical_device, configuration, &queue_infos)?;
662
663            let g_q = (0..graphics_count)
664                .map(|i| unsafe { device.get_device_queue(graphics_queue_family_id, i as u32) })
665                .collect::<_>();
666
667            let t_q = (0..transfer_count)
668                .map(|i| unsafe { device.get_device_queue(transfer_queue_family_id, i as u32) })
669                .collect::<_>();
670
671            let c_q = (0..compute_count)
672                .map(|i| unsafe { device.get_device_queue(compute_queue_family_id, i as u32) })
673                .collect::<_>();
674
675            Ok((
676                device,
677                [
678                    compute_queue_family_id,
679                    graphics_queue_family_id,
680                    transfer_queue_family_id,
681                ],
682                [c_q, g_q, t_q],
683            ))
684        }
685    }
686
687    fn create_logical_device(
688        &self,
689        physical_device: vk::PhysicalDevice,
690        mut configuration: DeviceConfiguration,
691        queue_infos: &[vk::DeviceQueueCreateInfoBuilder],
692    ) -> Result<erupt::DeviceLoader> {
693        let device_extensions = self.create_device_extensions(physical_device, &configuration)?;
694
695        #[cfg(feature = "tracing")]
696        Self::print_extensions("device", &device_extensions)?;
697
698        let robustness2_name = unsafe { CStr::from_ptr(vk::EXT_ROBUSTNESS_2_EXTENSION_NAME) };
699        let robustness2_enabled = device_extensions
700            .iter()
701            .any(|ext| unsafe { CStr::from_ptr(*ext) == robustness2_name });
702
703        let raytracing_name =
704            unsafe { CStr::from_ptr(vk::KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME) };
705        let raytracing_enabled = device_extensions
706            .iter()
707            .any(|ext| unsafe { CStr::from_ptr(*ext) == raytracing_name });
708
709        let acceleration_name =
710            unsafe { CStr::from_ptr(vk::KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME) };
711        let acceleration_structure_enabled = device_extensions
712            .iter()
713            .any(|ext| unsafe { CStr::from_ptr(*ext) == acceleration_name });
714
715        let (
716            physical_features,
717            physical_features11,
718            physical_features12,
719            physical_features_synchronization2,
720            physical_device_robustness2_features,
721            physical_features_raytracing,
722            physical_features_acceleration_structure,
723        ) = self.collect_physical_device_features(
724            physical_device,
725            robustness2_enabled,
726            raytracing_enabled,
727            acceleration_structure_enabled,
728        );
729
730        let features = if let Some(features) = configuration.features_v1_0.take() {
731            features
732        } else {
733            vk::PhysicalDeviceFeaturesBuilder::new()
734        };
735        let features11 = if let Some(features) = configuration.features_v1_1.take() {
736            features
737        } else {
738            vk::PhysicalDeviceVulkan11FeaturesBuilder::new()
739        };
740        let mut features12 = if let Some(features) = configuration.features_v1_2.take() {
741            features
742        } else {
743            vk::PhysicalDeviceVulkan12FeaturesBuilder::new()
744        };
745        let device_robustness2_features =
746            if let Some(features) = configuration.features_robustness2.take() {
747                features
748            } else {
749                vk::PhysicalDeviceRobustness2FeaturesEXTBuilder::new()
750            };
751        let features_raytracing = if let Some(features) = configuration.features_raytracing.take() {
752            features
753        } else {
754            vk::PhysicalDeviceRayTracingPipelineFeaturesKHRBuilder::new()
755        };
756        let features_acceleration_structure =
757            if let Some(features) = configuration.features_acceleration_structure.take() {
758                features
759            } else {
760                vk::PhysicalDeviceAccelerationStructureFeaturesKHRBuilder::new()
761            };
762
763        features12 = features12.timeline_semaphore(true);
764
765        #[cfg(feature = "vk-buffer-device-address")]
766        {
767            features12 = features12.buffer_device_address(true);
768        }
769
770        let features_synchronization2 =
771            vk::PhysicalDeviceSynchronization2FeaturesKHRBuilder::new().synchronization2(true);
772
773        check_features(
774            &physical_features,
775            &physical_features11,
776            &physical_features12,
777            &physical_features_synchronization2,
778            &physical_device_robustness2_features,
779            &physical_features_raytracing,
780            &physical_features_acceleration_structure,
781            &features,
782            &features11,
783            &features12,
784            &features_synchronization2,
785            &device_robustness2_features,
786            &features_raytracing,
787            &features_acceleration_structure,
788        )?;
789
790        let device_create_info = vk::DeviceCreateInfoBuilder::new()
791            .queue_create_infos(queue_infos)
792            .enabled_extension_names(&device_extensions)
793            .enabled_features(&features)
794            .extend_from(&features11)
795            .extend_from(&features12)
796            .extend_from(&features_synchronization2);
797
798        let device_create_info = if robustness2_enabled {
799            device_create_info.extend_from(&device_robustness2_features)
800        } else {
801            device_create_info
802        };
803
804        let device_create_info = if raytracing_enabled {
805            device_create_info.extend_from(&features_raytracing)
806        } else {
807            device_create_info
808        };
809
810        let device_create_info = if acceleration_structure_enabled {
811            device_create_info.extend_from(&features_acceleration_structure)
812        } else {
813            device_create_info
814        };
815
816        let device = unsafe {
817            erupt::DeviceLoader::new(&self.raw, physical_device, &device_create_info, None)
818        }?;
819
820        Ok(device)
821    }
822
823    #[cfg(feature = "tracing")]
824    fn print_extensions(what: &str, extensions: &[*const i8]) -> Result<()> {
825        info!("Loading {} extensions:", what);
826        for extension in extensions.iter() {
827            let ext = unsafe { CStr::from_ptr(*extension).to_str() }?;
828            info!("- {}", ext);
829        }
830        Ok(())
831    }
832
833    fn collect_physical_device_features(
834        &self,
835        physical_device: vk::PhysicalDevice,
836        robustness2_enabled: bool,
837        raytracing_enabled: bool,
838        acceleration_structure_enabled: bool,
839    ) -> (
840        vk::PhysicalDeviceFeatures,
841        vk::PhysicalDeviceVulkan11FeaturesBuilder,
842        vk::PhysicalDeviceVulkan12FeaturesBuilder,
843        vk::PhysicalDeviceSynchronization2FeaturesKHRBuilder,
844        vk::PhysicalDeviceRobustness2FeaturesEXTBuilder,
845        vk::PhysicalDeviceRayTracingPipelineFeaturesKHRBuilder,
846        vk::PhysicalDeviceAccelerationStructureFeaturesKHRBuilder,
847    ) {
848        let mut physical_features11 = vk::PhysicalDeviceVulkan11FeaturesBuilder::new();
849        let mut physical_features12 = vk::PhysicalDeviceVulkan12FeaturesBuilder::new();
850
851        let mut physical_feature_synchronization2 =
852            vk::PhysicalDeviceSynchronization2FeaturesKHRBuilder::new();
853
854        let mut physical_device_robustness2_features =
855            vk::PhysicalDeviceRobustness2FeaturesEXTBuilder::new();
856
857        let mut physical_features_raytracing =
858            vk::PhysicalDeviceRayTracingPipelineFeaturesKHRBuilder::new();
859        let mut physical_features_acceleration =
860            vk::PhysicalDeviceAccelerationStructureFeaturesKHRBuilder::new();
861
862        let physical_features = unsafe {
863            let physical_features = vk::PhysicalDeviceFeatures2Builder::new()
864                .extend_from(&mut physical_features11)
865                .extend_from(&mut physical_features12)
866                .extend_from(&mut physical_feature_synchronization2);
867
868            let physical_features = if robustness2_enabled {
869                physical_features.extend_from(&mut physical_device_robustness2_features)
870            } else {
871                physical_features
872            };
873
874            let physical_features = if raytracing_enabled {
875                physical_features.extend_from(&mut physical_features_raytracing)
876            } else {
877                physical_features
878            };
879
880            let physical_features = if acceleration_structure_enabled {
881                physical_features.extend_from(&mut physical_features_acceleration)
882            } else {
883                physical_features
884            };
885
886            self.raw
887                .get_physical_device_features2(physical_device, Some(physical_features.build()))
888        };
889
890        (
891            physical_features.features,
892            physical_features11,
893            physical_features12,
894            physical_feature_synchronization2,
895            physical_device_robustness2_features,
896            physical_features_raytracing,
897            physical_features_acceleration,
898        )
899    }
900
901    fn create_device_extensions(
902        &self,
903        physical_device: vk::PhysicalDevice,
904        configuration: &DeviceConfiguration,
905    ) -> Result<Vec<*const c_char>> {
906        let mut extensions: Vec<*const c_char> = configuration.extensions.clone();
907
908        extensions.push(vk::KHR_SWAPCHAIN_EXTENSION_NAME);
909        extensions.push(vk::KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
910
911        // Only keep available extensions.
912        let device_extensions = unsafe {
913            self.raw
914                .enumerate_device_extension_properties(physical_device, None, None)
915        }
916        .map_err(|err| {
917            #[cfg(feature = "tracing")]
918            error!(
919                "Unable to enumerate the device extension properties: {}",
920                err
921            );
922            AscheError::VkResult(err)
923        })?;
924
925        // Only keep available extensions.
926        Instance::retain_extensions(&device_extensions, &mut extensions);
927
928        Ok(extensions)
929    }
930
931    fn find_queue_family(
932        &self,
933        physical_device: vk::PhysicalDevice,
934        target_family: vk::QueueFlags,
935        queue_family_properties: &[vk::QueueFamilyProperties],
936    ) -> Result<u32> {
937        let mut queue_id = None;
938        for (id, family) in queue_family_properties.iter().enumerate() {
939            let surface_supported = unsafe {
940                self.raw.get_physical_device_surface_support_khr(
941                    physical_device,
942                    id.try_into()?,
943                    self.surface,
944                )
945            }
946            .map_err(|err| {
947                #[cfg(feature = "tracing")]
948                error!("Unable to get the physical device surface support: {}", err);
949                AscheError::VkResult(err)
950            })?;
951
952            match target_family {
953                vk::QueueFlags::GRAPHICS => {
954                    if family.queue_count > 0
955                        && family.queue_flags.contains(vk::QueueFlags::GRAPHICS)
956                        && surface_supported
957                    {
958                        queue_id = Some(id.try_into()?);
959                    }
960                }
961                vk::QueueFlags::TRANSFER => {
962                    if family.queue_count > 0
963                        && family.queue_flags.contains(vk::QueueFlags::TRANSFER)
964                        && (queue_id.is_none()
965                            || !family.queue_flags.contains(vk::QueueFlags::GRAPHICS)
966                                && !family.queue_flags.contains(vk::QueueFlags::COMPUTE))
967                    {
968                        queue_id = Some(id.try_into()?);
969                    }
970                }
971                vk::QueueFlags::COMPUTE => {
972                    if family.queue_count > 0
973                        && family.queue_flags.contains(vk::QueueFlags::COMPUTE)
974                        && (queue_id.is_none()
975                            || !family.queue_flags.contains(vk::QueueFlags::GRAPHICS))
976                    {
977                        queue_id = Some(id.try_into()?);
978                    }
979                }
980                _ => return Err(AscheError::QueueFamilyNotFound("unknown".to_string())),
981            }
982        }
983
984        if let Some(id) = queue_id {
985            #[cfg(feature = "tracing")]
986            info!("Selected {:?} queue has family index {}", target_family, id);
987
988            Ok(id)
989        } else {
990            match target_family {
991                vk::QueueFlags::COMPUTE => {
992                    Err(AscheError::QueueFamilyNotFound("compute".to_string()))
993                }
994                vk::QueueFlags::GRAPHICS => {
995                    Err(AscheError::QueueFamilyNotFound("graphic".to_string()))
996                }
997                vk::QueueFlags::TRANSFER => {
998                    Err(AscheError::QueueFamilyNotFound("transfer".to_string()))
999                }
1000                _ => Err(AscheError::QueueFamilyNotFound("unknown".to_string())),
1001            }
1002        }
1003    }
1004}
1005
1006macro_rules! impl_feature_assemble {
1007    (
1008        $present:ident, $wanted:ident, $present_vector:ident, $wanted_vector:ident;
1009        {
1010            $($name:ident)*
1011        }
1012    ) => {
1013        $(if $present.$name != 0 {
1014            $present_vector.push(stringify!($name))
1015        })*
1016        $(if $wanted.$name != 0 {
1017            $wanted_vector.push(stringify!($name))
1018        })*
1019    };
1020}
1021
1022#[allow(unused_mut)]
1023#[allow(clippy::too_many_arguments)]
1024fn check_features(
1025    physical_features: &vk::PhysicalDeviceFeatures,
1026    physical_features11: &vk::PhysicalDeviceVulkan11FeaturesBuilder,
1027    physical_features12: &vk::PhysicalDeviceVulkan12FeaturesBuilder,
1028    physical_features_synchronization2: &vk::PhysicalDeviceSynchronization2FeaturesKHRBuilder,
1029    physical_device_robustness2_features: &vk::PhysicalDeviceRobustness2FeaturesEXTBuilder,
1030    physical_features_raytracing: &vk::PhysicalDeviceRayTracingPipelineFeaturesKHRBuilder,
1031    physical_features_acceleration_structure: &vk::PhysicalDeviceAccelerationStructureFeaturesKHRBuilder,
1032    features: &vk::PhysicalDeviceFeaturesBuilder,
1033    features11: &vk::PhysicalDeviceVulkan11FeaturesBuilder,
1034    features12: &vk::PhysicalDeviceVulkan12FeaturesBuilder,
1035    features_synchronization2: &vk::PhysicalDeviceSynchronization2FeaturesKHRBuilder,
1036    device_robustness2_features: &vk::PhysicalDeviceRobustness2FeaturesEXTBuilder,
1037    features_raytracing: &vk::PhysicalDeviceRayTracingPipelineFeaturesKHRBuilder,
1038    features_acceleration_structure: &vk::PhysicalDeviceAccelerationStructureFeaturesKHRBuilder,
1039) -> Result<()> {
1040    let mut physical_features_list: Vec<&str> = Vec::with_capacity(54);
1041    let mut physical_features11_list: Vec<&str> = Vec::with_capacity(11);
1042    let mut physical_features12_list: Vec<&str> = Vec::with_capacity(46);
1043    let mut physical_features_synchronization2_list: Vec<&str> = Vec::with_capacity(1);
1044    let mut physical_device_robustness2_features_list: Vec<&str> = Vec::with_capacity(3);
1045    let mut physical_features_raytracing_list: Vec<&str> = Vec::with_capacity(5);
1046    let mut physical_features_acceleration_structure_list: Vec<&str> = Vec::with_capacity(5);
1047
1048    let mut features_list: Vec<&str> = Vec::with_capacity(54);
1049    let mut features11_list: Vec<&str> = Vec::with_capacity(11);
1050    let mut features12_list: Vec<&str> = Vec::with_capacity(46);
1051    let mut features_synchronization2_list: Vec<&str> = Vec::with_capacity(1);
1052    let mut device_robustness2_features_list: Vec<&str> = Vec::with_capacity(3);
1053    let mut features_raytracing_list: Vec<&str> = Vec::with_capacity(5);
1054    let mut features_acceleration_structure_list: Vec<&str> = Vec::with_capacity(5);
1055
1056    impl_feature_assemble!(
1057        physical_features, features, physical_features_list, features_list;
1058        {
1059            robust_buffer_access
1060            full_draw_index_uint32
1061            image_cube_array
1062            independent_blend
1063            geometry_shader
1064            tessellation_shader
1065            sample_rate_shading
1066            dual_src_blend
1067            logic_op
1068            multi_draw_indirect
1069            draw_indirect_first_instance
1070            depth_clamp
1071            depth_bias_clamp
1072            fill_mode_non_solid
1073            depth_bounds
1074            wide_lines
1075            large_points
1076            alpha_to_one
1077            multi_viewport
1078            sampler_anisotropy
1079            texture_compression_etc2
1080            texture_compression_astc_ldr
1081            texture_compression_bc
1082            occlusion_query_precise
1083            pipeline_statistics_query
1084            vertex_pipeline_stores_and_atomics
1085            fragment_stores_and_atomics
1086            shader_tessellation_and_geometry_point_size
1087            shader_image_gather_extended
1088            shader_storage_image_extended_formats
1089            shader_storage_image_multisample
1090            shader_storage_image_read_without_format
1091            shader_storage_image_write_without_format
1092            shader_uniform_buffer_array_dynamic_indexing
1093            shader_sampled_image_array_dynamic_indexing
1094            shader_storage_buffer_array_dynamic_indexing
1095            shader_storage_image_array_dynamic_indexing
1096            shader_clip_distance
1097            shader_cull_distance
1098            shader_float64
1099            shader_int64
1100            shader_int16
1101            shader_resource_residency
1102            shader_resource_min_lod
1103            sparse_binding
1104            sparse_residency_buffer
1105            sparse_residency_image2_d
1106            sparse_residency_image3_d
1107            sparse_residency2_samples
1108            sparse_residency4_samples
1109            sparse_residency8_samples
1110            sparse_residency16_samples
1111            sparse_residency_aliased
1112            variable_multisample_rate
1113            inherited_queries
1114        }
1115    );
1116
1117    impl_feature_assemble!(
1118        physical_features11, features11, physical_features11_list, features11_list;
1119        {
1120            storage_buffer16_bit_access
1121            uniform_and_storage_buffer16_bit_access
1122            storage_push_constant16
1123            storage_input_output16
1124            multiview
1125            multiview_geometry_shader
1126            multiview_tessellation_shader
1127            variable_pointers_storage_buffer
1128            variable_pointers
1129            protected_memory
1130            sampler_ycbcr_conversion
1131            shader_draw_parameters
1132        }
1133    );
1134
1135    impl_feature_assemble!(
1136        physical_features12, features12, physical_features12_list, features12_list;
1137        {
1138            sampler_mirror_clamp_to_edge
1139            draw_indirect_count
1140            storage_buffer8_bit_access
1141            uniform_and_storage_buffer8_bit_access
1142            storage_push_constant8
1143            shader_buffer_int64_atomics
1144            shader_shared_int64_atomics
1145            shader_float16
1146            shader_int8
1147            descriptor_indexing
1148            shader_input_attachment_array_dynamic_indexing
1149            shader_uniform_texel_buffer_array_dynamic_indexing
1150            shader_storage_texel_buffer_array_dynamic_indexing
1151            shader_uniform_buffer_array_non_uniform_indexing
1152            shader_sampled_image_array_non_uniform_indexing
1153            shader_storage_buffer_array_non_uniform_indexing
1154            shader_storage_image_array_non_uniform_indexing
1155            shader_input_attachment_array_non_uniform_indexing
1156            shader_uniform_texel_buffer_array_non_uniform_indexing
1157            shader_storage_texel_buffer_array_non_uniform_indexing
1158            descriptor_binding_uniform_buffer_update_after_bind
1159            descriptor_binding_sampled_image_update_after_bind
1160            descriptor_binding_storage_image_update_after_bind
1161            descriptor_binding_storage_buffer_update_after_bind
1162            descriptor_binding_uniform_texel_buffer_update_after_bind
1163            descriptor_binding_storage_texel_buffer_update_after_bind
1164            descriptor_binding_update_unused_while_pending
1165            descriptor_binding_partially_bound
1166            descriptor_binding_variable_descriptor_count
1167            runtime_descriptor_array
1168            sampler_filter_minmax
1169            scalar_block_layout
1170            imageless_framebuffer
1171            uniform_buffer_standard_layout
1172            shader_subgroup_extended_types
1173            separate_depth_stencil_layouts
1174            host_query_reset
1175            timeline_semaphore
1176            buffer_device_address
1177            buffer_device_address_capture_replay
1178            buffer_device_address_multi_device
1179            vulkan_memory_model
1180            vulkan_memory_model_device_scope
1181            vulkan_memory_model_availability_visibility_chains
1182            shader_output_viewport_index
1183            shader_output_layer
1184            subgroup_broadcast_dynamic_id
1185        }
1186    );
1187
1188    impl_feature_assemble!(
1189        physical_features_synchronization2, features_synchronization2, physical_features_synchronization2_list, features_synchronization2_list;
1190        {
1191            synchronization2
1192        }
1193    );
1194
1195    impl_feature_assemble!(
1196        physical_device_robustness2_features, device_robustness2_features, physical_device_robustness2_features_list, device_robustness2_features_list;
1197        {
1198            robust_buffer_access2
1199            robust_image_access2
1200            null_descriptor
1201        }
1202    );
1203
1204    impl_feature_assemble!(
1205        physical_features_raytracing, features_raytracing, physical_features_raytracing_list, features_raytracing_list;
1206        {
1207            ray_tracing_pipeline
1208            ray_tracing_pipeline_shader_group_handle_capture_replay
1209            ray_tracing_pipeline_shader_group_handle_capture_replay_mixed
1210            ray_tracing_pipeline_trace_rays_indirect
1211            ray_traversal_primitive_culling
1212        }
1213    );
1214
1215    impl_feature_assemble!(
1216        physical_features_acceleration_structure, features_acceleration_structure, physical_features_acceleration_structure_list, features_acceleration_structure_list;
1217        {
1218            acceleration_structure
1219            acceleration_structure_capture_replay
1220            acceleration_structure_host_commands
1221            acceleration_structure_indirect_build
1222            descriptor_binding_acceleration_structure_update_after_bind
1223        }
1224    );
1225
1226    let mut missing_features = false;
1227
1228    #[cfg(feature = "tracing")]
1229    if !features_list.is_empty() {
1230        info!("Enabling Vulkan 1.0 features:");
1231        features_list.retain(|&wanted| {
1232            let found = physical_features_list
1233                .iter()
1234                .any(|present| *present == wanted);
1235            if found {
1236                info!("- {}", wanted);
1237                true
1238            } else {
1239                #[cfg(feature = "tracing")]
1240                error!("Unable to find Vulkan 1.0 feature: {}", wanted);
1241                missing_features = true;
1242                false
1243            }
1244        });
1245    }
1246
1247    #[cfg(feature = "tracing")]
1248    if !features11_list.is_empty() {
1249        info!("Enabling Vulkan 1.1 features:");
1250        features11_list.retain(|&wanted| {
1251            let found = physical_features11_list
1252                .iter()
1253                .any(|present| *present == wanted);
1254            if found {
1255                info!("- {}", wanted);
1256                true
1257            } else {
1258                #[cfg(feature = "tracing")]
1259                error!("Unable to find Vulkan 1.1 feature: {}", wanted);
1260                missing_features = true;
1261                false
1262            }
1263        });
1264    }
1265
1266    #[cfg(feature = "tracing")]
1267    if !features12_list.is_empty() {
1268        info!("Enabling Vulkan 1.2 features:");
1269        features12_list.retain(|&wanted| {
1270            let found = physical_features12_list
1271                .iter()
1272                .any(|present| *present == wanted);
1273            if found {
1274                info!("- {}", wanted);
1275                true
1276            } else {
1277                #[cfg(feature = "tracing")]
1278                error!("Unable to find Vulkan 1.2 feature: {}", wanted);
1279                missing_features = true;
1280                false
1281            }
1282        });
1283    }
1284
1285    #[cfg(feature = "tracing")]
1286    if !features_synchronization2_list.is_empty() {
1287        info!("Enabling VK_KHR_synchronization2 features:");
1288        features_synchronization2_list.retain(|&wanted| {
1289            let found = physical_features_synchronization2_list
1290                .iter()
1291                .any(|present| *present == wanted);
1292            if found {
1293                info!("- {}", wanted);
1294                true
1295            } else {
1296                #[cfg(feature = "tracing")]
1297                error!("Unable to find VK_KHR_synchronization2 feature: {}", wanted);
1298                missing_features = true;
1299                false
1300            }
1301        });
1302    }
1303
1304    #[cfg(feature = "tracing")]
1305    if !device_robustness2_features_list.is_empty() {
1306        info!("Enabling VK_EXT_robustness2 features:");
1307        device_robustness2_features_list.retain(|&wanted| {
1308            let found = physical_device_robustness2_features_list
1309                .iter()
1310                .any(|present| *present == wanted);
1311            if found {
1312                info!("- {}", wanted);
1313                true
1314            } else {
1315                #[cfg(feature = "tracing")]
1316                error!("Unable to find VK_EXT_robustness2 feature: {}", wanted);
1317                missing_features = true;
1318                false
1319            }
1320        });
1321    }
1322
1323    #[cfg(feature = "tracing")]
1324    if !features_raytracing_list.is_empty() {
1325        info!("Enabling VK_KHR_ray_tracing_pipeline features:");
1326        features_raytracing_list.retain(|&wanted| {
1327            let found = physical_features_raytracing_list
1328                .iter()
1329                .any(|present| *present == wanted);
1330            if found {
1331                info!("- {}", wanted);
1332                true
1333            } else {
1334                #[cfg(feature = "tracing")]
1335                error!(
1336                    "Unable to find VK_KHR_ray_tracing_pipeline feature: {}",
1337                    wanted
1338                );
1339                missing_features = true;
1340                false
1341            }
1342        });
1343    }
1344
1345    #[cfg(feature = "tracing")]
1346    if !features_acceleration_structure_list.is_empty() {
1347        info!("Enabling VK_KHR_acceleration_structure features:");
1348        features_acceleration_structure_list.retain(|&wanted| {
1349            let found = physical_features_acceleration_structure_list
1350                .iter()
1351                .any(|present| *present == wanted);
1352            if found {
1353                info!("- {}", wanted);
1354                true
1355            } else {
1356                #[cfg(feature = "tracing")]
1357                error!(
1358                    "Unable to find VK_KHR_acceleration_structure feature: {}",
1359                    wanted
1360                );
1361                missing_features = true;
1362                false
1363            }
1364        });
1365    }
1366
1367    if missing_features {
1368        Err(AscheError::DeviceFeatureMissing)
1369    } else {
1370        Ok(())
1371    }
1372}
1373
1374impl Drop for Instance {
1375    fn drop(&mut self) {
1376        unsafe {
1377            #[cfg(debug_assertions)]
1378            self.raw
1379                .destroy_debug_utils_messenger_ext(Some(self.debug_messenger), None);
1380
1381            self.raw.destroy_surface_khr(Some(self.surface), None);
1382            self.raw.destroy_instance(None);
1383        };
1384    }
1385}