vulkanalia_bootstrap/
device.rs

1use crate::Instance;
2use std::borrow::Cow;
3use std::cell::RefCell;
4use std::cmp::Ordering;
5use std::collections::BTreeSet;
6use std::fmt::Debug;
7use std::hint::unreachable_unchecked;
8use std::ops::Deref;
9use std::sync::Arc;
10use vulkanalia::Version;
11use vulkanalia::vk::{
12    self, DeviceV1_0, HasBuilder, InstanceV1_0, InstanceV1_1, KhrSurfaceExtension,
13};
14use vulkanalia::vk::{AllocationCallbacks, DeviceV1_1};
15
16fn supports_features(
17    supported: &vk::PhysicalDeviceFeatures,
18    requested: &vk::PhysicalDeviceFeatures,
19    features_supported: &GenericFeatureChain,
20    features_requested: &GenericFeatureChain,
21) -> bool {
22    macro_rules! check_feature {
23        ($feature: ident) => {
24            if requested.$feature == vk::TRUE && supported.$feature == vk::FALSE {
25                return false;
26            }
27        };
28    }
29
30    check_feature!(robust_buffer_access);
31    check_feature!(full_draw_index_uint32);
32    check_feature!(image_cube_array);
33    check_feature!(independent_blend);
34    check_feature!(geometry_shader);
35    check_feature!(tessellation_shader);
36    check_feature!(sample_rate_shading);
37    check_feature!(dual_src_blend);
38    check_feature!(logic_op);
39    check_feature!(multi_draw_indirect);
40    check_feature!(draw_indirect_first_instance);
41    check_feature!(depth_clamp);
42    check_feature!(depth_bias_clamp);
43    check_feature!(fill_mode_non_solid);
44    check_feature!(depth_bounds);
45    check_feature!(wide_lines);
46    check_feature!(large_points);
47    check_feature!(alpha_to_one);
48    check_feature!(multi_viewport);
49    check_feature!(sampler_anisotropy);
50    check_feature!(texture_compression_etc2);
51    check_feature!(texture_compression_astc_ldr);
52    check_feature!(texture_compression_bc);
53    check_feature!(occlusion_query_precise);
54    check_feature!(pipeline_statistics_query);
55    check_feature!(vertex_pipeline_stores_and_atomics);
56    check_feature!(fragment_stores_and_atomics);
57    check_feature!(shader_tessellation_and_geometry_point_size);
58    check_feature!(shader_image_gather_extended);
59    check_feature!(shader_storage_image_extended_formats);
60    check_feature!(shader_storage_image_multisample);
61    check_feature!(shader_storage_image_read_without_format);
62    check_feature!(shader_storage_image_write_without_format);
63    check_feature!(shader_uniform_buffer_array_dynamic_indexing);
64    check_feature!(shader_sampled_image_array_dynamic_indexing);
65    check_feature!(shader_storage_buffer_array_dynamic_indexing);
66    check_feature!(shader_storage_image_array_dynamic_indexing);
67    check_feature!(shader_clip_distance);
68    check_feature!(shader_cull_distance);
69    check_feature!(shader_float64);
70    check_feature!(shader_int64);
71    check_feature!(shader_int16);
72    check_feature!(shader_resource_residency);
73    check_feature!(shader_resource_min_lod);
74    check_feature!(sparse_binding);
75    check_feature!(sparse_residency_buffer);
76    check_feature!(sparse_residency_image_2d);
77    check_feature!(sparse_residency_image_3d);
78    check_feature!(sparse_residency2_samples);
79    check_feature!(sparse_residency4_samples);
80    check_feature!(sparse_residency8_samples);
81    check_feature!(sparse_residency16_samples);
82    check_feature!(sparse_residency_aliased);
83    check_feature!(variable_multisample_rate);
84    check_feature!(inherited_queries);
85
86    features_supported.match_all(features_requested)
87}
88
89#[inline]
90fn get_first_queue_index(
91    families: &[vk::QueueFamilyProperties],
92    desired_flags: vk::QueueFlags,
93) -> Option<usize> {
94    families
95        .iter()
96        .position(|f| f.queue_flags.contains(desired_flags))
97}
98
99/// Finds the queue which is separate from the graphics queue and has the desired flag and not the
100/// undesired flag, but will select it if no better options are available for compute support. Returns
101/// QUEUE_INDEX_MAX_VALUE if none is found.
102fn get_separate_queue_index(
103    families: &[vk::QueueFamilyProperties],
104    desired_flags: vk::QueueFlags,
105    undesired_flags: vk::QueueFlags,
106) -> Option<usize> {
107    let mut index = None;
108    for (i, family) in families.iter().enumerate() {
109        if family.queue_flags.contains(desired_flags)
110            && !family.queue_flags.contains(vk::QueueFlags::GRAPHICS)
111        {
112            if !family.queue_flags.contains(undesired_flags) {
113                return Some(i);
114            } else {
115                index = Some(i);
116            }
117        }
118    }
119
120    index
121}
122
123/// finds the first queue which supports only the desired flag (not graphics or transfer). Returns QUEUE_INDEX_MAX_VALUE if none is found.
124fn get_dedicated_queue_index(
125    families: &[vk::QueueFamilyProperties],
126    desired_flags: vk::QueueFlags,
127    undesired_flags: vk::QueueFlags,
128) -> Option<usize> {
129    families.iter().position(|f| {
130        f.queue_flags.contains(desired_flags)
131            && !f.queue_flags.contains(vk::QueueFlags::GRAPHICS)
132            && !f.queue_flags.contains(undesired_flags)
133    })
134}
135
136fn get_present_queue_index(
137    instance: &vulkanalia::Instance,
138    device: vk::PhysicalDevice,
139    surface: Option<vk::SurfaceKHR>,
140    families: &[vk::QueueFamilyProperties],
141) -> Option<usize> {
142    for (i, _) in families.iter().enumerate() {
143        if let Some(surface) = surface {
144            let present_support = unsafe {
145                instance.get_physical_device_surface_support_khr(device, i as u32, surface)
146            };
147
148            if let Ok(present_support) = present_support {
149                if present_support {
150                    return Some(i);
151                }
152            }
153        }
154    }
155
156    None
157}
158
159fn check_device_extension_support(
160    available_extensions: &BTreeSet<vk::ExtensionName>,
161    required_extensions: &BTreeSet<vk::ExtensionName>,
162) -> BTreeSet<vk::ExtensionName> {
163    let mut extensions_to_enable = BTreeSet::<vk::ExtensionName>::new();
164
165    for avail_ext in available_extensions {
166        for req_ext in required_extensions {
167            if avail_ext == req_ext {
168                extensions_to_enable.insert(*req_ext);
169                break;
170            }
171        }
172    }
173
174    extensions_to_enable
175}
176
177#[repr(u8)]
178#[derive(Default, Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
179pub enum PreferredDeviceType {
180    Other = 0,
181    Integrated = 1,
182    #[default]
183    Discrete = 2,
184    VirtualGpu = 3,
185    Cpu = 4,
186}
187
188#[derive(Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
189pub enum Suitable {
190    #[default]
191    Yes,
192    Partial,
193    No,
194}
195
196#[derive(Default, Debug)]
197pub struct PhysicalDevice {
198    name: String,
199    physical_device: vk::PhysicalDevice,
200    surface: Option<vk::SurfaceKHR>,
201
202    features: vk::PhysicalDeviceFeatures,
203    pub properties: vk::PhysicalDeviceProperties,
204    memory_properties: vk::PhysicalDeviceMemoryProperties,
205    extensions_to_enable: BTreeSet<vk::ExtensionName>,
206    available_extensions: BTreeSet<vk::ExtensionName>,
207    queue_families: Vec<vk::QueueFamilyProperties>,
208    defer_surface_initialization: bool,
209    properties2_ext_enabled: bool,
210    //supported_format_properties: HashMap<vk::Format, vk::FormatProperties>,
211    suitable: Suitable,
212    supported_features_chain: GenericFeatureChain,
213    requested_features_chain: GenericFeatureChain,
214}
215
216impl AsRef<vk::PhysicalDevice> for PhysicalDevice {
217    fn as_ref(&self) -> &vk::PhysicalDevice {
218        &self.physical_device
219    }
220}
221
222impl Eq for PhysicalDevice {}
223
224impl PartialEq<Self> for PhysicalDevice {
225    fn eq(&self, other: &Self) -> bool {
226        self.name.eq(&other.name)
227            && self.physical_device.eq(&other.physical_device)
228            && self.suitable.eq(&other.suitable)
229    }
230}
231
232impl PartialOrd for PhysicalDevice {
233    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
234        Some(self.cmp(other))
235    }
236}
237
238impl Ord for PhysicalDevice {
239    fn cmp(&self, other: &Self) -> Ordering {
240        self.suitable.cmp(&other.suitable)
241    }
242}
243
244impl PhysicalDevice {
245    pub fn msaa_samples(&self) -> vk::SampleCountFlags {
246        let limits = &self.properties.limits;
247        let counts =
248            limits.framebuffer_color_sample_counts & limits.framebuffer_depth_sample_counts;
249
250        if counts.contains(vk::SampleCountFlags::_64) {
251            return vk::SampleCountFlags::_64;
252        }
253
254        if counts.contains(vk::SampleCountFlags::_32) {
255            return vk::SampleCountFlags::_32;
256        }
257
258        if counts.contains(vk::SampleCountFlags::_16) {
259            return vk::SampleCountFlags::_16;
260        }
261
262        if counts.contains(vk::SampleCountFlags::_8) {
263            return vk::SampleCountFlags::_8;
264        }
265
266        if counts.contains(vk::SampleCountFlags::_4) {
267            return vk::SampleCountFlags::_4;
268        }
269
270        if counts.contains(vk::SampleCountFlags::_2) {
271            return vk::SampleCountFlags::_2;
272        }
273
274        vk::SampleCountFlags::_1
275    }
276    pub fn enable_extension_if_present(&mut self, extension: vk::ExtensionName) -> bool {
277        let extension = extension.into();
278
279        if self.available_extensions.contains(&extension) {
280            self.extensions_to_enable.insert(extension)
281        } else {
282            false
283        }
284    }
285
286    pub fn enable_extensions_if_present<I: IntoIterator<Item = vk::ExtensionName>>(
287        &mut self,
288        extensions: I,
289    ) -> bool {
290        let extensions = BTreeSet::from_iter(extensions);
291        let intersection: BTreeSet<_> = self
292            .available_extensions
293            .intersection(&extensions)
294            .cloned()
295            .collect();
296
297        if intersection.len() == extensions.len() {
298            self.extensions_to_enable.extend(intersection);
299            true
300        } else {
301            false
302        }
303    }
304}
305
306// TODO: proper transmute via ash
307//region vulkanfeatures
308#[derive(Debug, Clone)]
309pub enum VulkanPhysicalDeviceFeature2 {
310    PhysicalDeviceVulkan11(vk::PhysicalDeviceVulkan11Features),
311    PhysicalDeviceVulkan12(vk::PhysicalDeviceVulkan12Features),
312    PhysicalDeviceVulkan13(vk::PhysicalDeviceVulkan13Features),
313}
314
315fn match_features(
316    requested: &VulkanPhysicalDeviceFeature2,
317    supported: &VulkanPhysicalDeviceFeature2,
318) -> bool {
319    assert_eq!(requested.s_type(), supported.s_type());
320
321    match (requested, supported) {
322        (
323            VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(r),
324            VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(s),
325        ) => {
326            if r.storage_buffer_16bit_access == vk::TRUE
327                && s.storage_buffer_16bit_access == vk::FALSE
328            {
329                return false;
330            }
331            if r.uniform_and_storage_buffer_16bit_access == vk::TRUE
332                && s.uniform_and_storage_buffer_16bit_access == vk::FALSE
333            {
334                return false;
335            }
336            if r.storage_push_constant16 == vk::TRUE && s.storage_push_constant16 == vk::FALSE {
337                return false;
338            }
339            if r.storage_input_output16 == vk::TRUE && s.storage_input_output16 == vk::FALSE {
340                return false;
341            }
342            if r.multiview == vk::TRUE && s.multiview == vk::FALSE {
343                return false;
344            }
345            if r.multiview_geometry_shader == vk::TRUE && s.multiview_geometry_shader == vk::FALSE {
346                return false;
347            }
348            if r.multiview_tessellation_shader == vk::TRUE
349                && s.multiview_tessellation_shader == vk::FALSE
350            {
351                return false;
352            }
353            if r.variable_pointers_storage_buffer == vk::TRUE
354                && s.variable_pointers_storage_buffer == vk::FALSE
355            {
356                return false;
357            }
358            if r.variable_pointers == vk::TRUE && s.variable_pointers == vk::FALSE {
359                return false;
360            }
361            if r.protected_memory == vk::TRUE && s.protected_memory == vk::FALSE {
362                return false;
363            }
364            if r.sampler_ycbcr_conversion == vk::TRUE && s.sampler_ycbcr_conversion == vk::FALSE {
365                return false;
366            }
367            if r.shader_draw_parameters == vk::TRUE && s.shader_draw_parameters == vk::FALSE {
368                return false;
369            }
370            true
371        }
372        (
373            VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(r),
374            VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(s),
375        ) => {
376            if r.sampler_mirror_clamp_to_edge == vk::TRUE
377                && s.sampler_mirror_clamp_to_edge == vk::FALSE
378            {
379                return false;
380            }
381            if r.draw_indirect_count == vk::TRUE && s.draw_indirect_count == vk::FALSE {
382                return false;
383            }
384            if r.storage_buffer_8bit_access == vk::TRUE && s.storage_buffer_8bit_access == vk::FALSE
385            {
386                return false;
387            }
388            if r.uniform_and_storage_buffer_8bit_access == vk::TRUE
389                && s.uniform_and_storage_buffer_8bit_access == vk::FALSE
390            {
391                return false;
392            }
393            if r.storage_push_constant8 == vk::TRUE && s.storage_push_constant8 == vk::FALSE {
394                return false;
395            }
396            if r.shader_buffer_int64_atomics == vk::TRUE
397                && s.shader_buffer_int64_atomics == vk::FALSE
398            {
399                return false;
400            }
401            if r.shader_shared_int64_atomics == vk::TRUE
402                && s.shader_shared_int64_atomics == vk::FALSE
403            {
404                return false;
405            }
406            if r.shader_float16 == vk::TRUE && s.shader_float16 == vk::FALSE {
407                return false;
408            }
409            if r.shader_int8 == vk::TRUE && s.shader_int8 == vk::FALSE {
410                return false;
411            }
412            if r.descriptor_indexing == vk::TRUE && s.descriptor_indexing == vk::FALSE {
413                return false;
414            }
415            if r.shader_input_attachment_array_dynamic_indexing == vk::TRUE
416                && s.shader_input_attachment_array_dynamic_indexing == vk::FALSE
417            {
418                return false;
419            }
420            if r.shader_uniform_texel_buffer_array_dynamic_indexing == vk::TRUE
421                && s.shader_uniform_texel_buffer_array_dynamic_indexing == vk::FALSE
422            {
423                return false;
424            }
425            if r.shader_storage_texel_buffer_array_dynamic_indexing == vk::TRUE
426                && s.shader_storage_texel_buffer_array_dynamic_indexing == vk::FALSE
427            {
428                return false;
429            }
430            if r.shader_uniform_buffer_array_non_uniform_indexing == vk::TRUE
431                && s.shader_uniform_buffer_array_non_uniform_indexing == vk::FALSE
432            {
433                return false;
434            }
435            if r.shader_sampled_image_array_non_uniform_indexing == vk::TRUE
436                && s.shader_sampled_image_array_non_uniform_indexing == vk::FALSE
437            {
438                return false;
439            }
440            if r.shader_storage_buffer_array_non_uniform_indexing == vk::TRUE
441                && s.shader_storage_buffer_array_non_uniform_indexing == vk::FALSE
442            {
443                return false;
444            }
445            if r.shader_storage_image_array_non_uniform_indexing == vk::TRUE
446                && s.shader_storage_image_array_non_uniform_indexing == vk::FALSE
447            {
448                return false;
449            }
450            if r.shader_input_attachment_array_non_uniform_indexing == vk::TRUE
451                && s.shader_input_attachment_array_non_uniform_indexing == vk::FALSE
452            {
453                return false;
454            }
455            if r.shader_uniform_texel_buffer_array_non_uniform_indexing == vk::TRUE
456                && s.shader_uniform_texel_buffer_array_non_uniform_indexing == vk::FALSE
457            {
458                return false;
459            }
460            if r.shader_storage_texel_buffer_array_non_uniform_indexing == vk::TRUE
461                && s.shader_storage_texel_buffer_array_non_uniform_indexing == vk::FALSE
462            {
463                return false;
464            }
465            if r.descriptor_binding_uniform_buffer_update_after_bind == vk::TRUE
466                && s.descriptor_binding_uniform_buffer_update_after_bind == vk::FALSE
467            {
468                return false;
469            }
470            if r.descriptor_binding_sampled_image_update_after_bind == vk::TRUE
471                && s.descriptor_binding_sampled_image_update_after_bind == vk::FALSE
472            {
473                return false;
474            }
475            if r.descriptor_binding_storage_image_update_after_bind == vk::TRUE
476                && s.descriptor_binding_storage_image_update_after_bind == vk::FALSE
477            {
478                return false;
479            }
480            if r.descriptor_binding_storage_buffer_update_after_bind == vk::TRUE
481                && s.descriptor_binding_storage_buffer_update_after_bind == vk::FALSE
482            {
483                return false;
484            }
485            if r.descriptor_binding_uniform_texel_buffer_update_after_bind == vk::TRUE
486                && s.descriptor_binding_uniform_texel_buffer_update_after_bind == vk::FALSE
487            {
488                return false;
489            }
490            if r.descriptor_binding_storage_texel_buffer_update_after_bind == vk::TRUE
491                && s.descriptor_binding_storage_texel_buffer_update_after_bind == vk::FALSE
492            {
493                return false;
494            }
495            if r.descriptor_binding_update_unused_while_pending == vk::TRUE
496                && s.descriptor_binding_update_unused_while_pending == vk::FALSE
497            {
498                return false;
499            }
500            if r.descriptor_binding_partially_bound == vk::TRUE
501                && s.descriptor_binding_partially_bound == vk::FALSE
502            {
503                return false;
504            }
505            if r.descriptor_binding_variable_descriptor_count == vk::TRUE
506                && s.descriptor_binding_variable_descriptor_count == vk::FALSE
507            {
508                return false;
509            }
510            if r.runtime_descriptor_array == vk::TRUE && s.runtime_descriptor_array == vk::FALSE {
511                return false;
512            }
513            if r.sampler_filter_minmax == vk::TRUE && s.sampler_filter_minmax == vk::FALSE {
514                return false;
515            }
516            if r.scalar_block_layout == vk::TRUE && s.scalar_block_layout == vk::FALSE {
517                return false;
518            }
519            if r.imageless_framebuffer == vk::TRUE && s.imageless_framebuffer == vk::FALSE {
520                return false;
521            }
522            if r.uniform_buffer_standard_layout == vk::TRUE
523                && s.uniform_buffer_standard_layout == vk::FALSE
524            {
525                return false;
526            }
527            if r.shader_subgroup_extended_types == vk::TRUE
528                && s.shader_subgroup_extended_types == vk::FALSE
529            {
530                return false;
531            }
532            if r.separate_depth_stencil_layouts == vk::TRUE
533                && s.separate_depth_stencil_layouts == vk::FALSE
534            {
535                return false;
536            }
537            if r.host_query_reset == vk::TRUE && s.host_query_reset == vk::FALSE {
538                return false;
539            }
540            if r.timeline_semaphore == vk::TRUE && s.timeline_semaphore == vk::FALSE {
541                return false;
542            }
543            if r.buffer_device_address == vk::TRUE && s.buffer_device_address == vk::FALSE {
544                return false;
545            }
546            if r.buffer_device_address_capture_replay == vk::TRUE
547                && s.buffer_device_address_capture_replay == vk::FALSE
548            {
549                return false;
550            }
551            if r.buffer_device_address_multi_device == vk::TRUE
552                && s.buffer_device_address_multi_device == vk::FALSE
553            {
554                return false;
555            }
556            if r.vulkan_memory_model == vk::TRUE && s.vulkan_memory_model == vk::FALSE {
557                return false;
558            }
559            if r.vulkan_memory_model_device_scope == vk::TRUE
560                && s.vulkan_memory_model_device_scope == vk::FALSE
561            {
562                return false;
563            }
564            if r.vulkan_memory_model_availability_visibility_chains == vk::TRUE
565                && s.vulkan_memory_model_availability_visibility_chains == vk::FALSE
566            {
567                return false;
568            }
569            if r.shader_output_viewport_index == vk::TRUE
570                && s.shader_output_viewport_index == vk::FALSE
571            {
572                return false;
573            }
574            if r.shader_output_layer == vk::TRUE && s.shader_output_layer == vk::FALSE {
575                return false;
576            }
577            if r.subgroup_broadcast_dynamic_id == vk::TRUE
578                && s.subgroup_broadcast_dynamic_id == vk::FALSE
579            {
580                return false;
581            }
582            true
583        }
584        (
585            VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(r),
586            VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(s),
587        ) => {
588            if r.robust_image_access == vk::TRUE && s.robust_image_access == vk::FALSE {
589                return false;
590            }
591            if r.inline_uniform_block == vk::TRUE && s.inline_uniform_block == vk::FALSE {
592                return false;
593            }
594            if r.descriptor_binding_inline_uniform_block_update_after_bind == vk::TRUE
595                && s.descriptor_binding_inline_uniform_block_update_after_bind == vk::FALSE
596            {
597                return false;
598            }
599            if r.pipeline_creation_cache_control == vk::TRUE
600                && s.pipeline_creation_cache_control == vk::FALSE
601            {
602                return false;
603            }
604            if r.private_data == vk::TRUE && s.private_data == vk::FALSE {
605                return false;
606            }
607            if r.shader_demote_to_helper_invocation == vk::TRUE
608                && s.shader_demote_to_helper_invocation == vk::FALSE
609            {
610                return false;
611            }
612            if r.shader_terminate_invocation == vk::TRUE
613                && s.shader_terminate_invocation == vk::FALSE
614            {
615                return false;
616            }
617            if r.subgroup_size_control == vk::TRUE && s.subgroup_size_control == vk::FALSE {
618                return false;
619            }
620            if r.compute_full_subgroups == vk::TRUE && s.compute_full_subgroups == vk::FALSE {
621                return false;
622            }
623            if r.synchronization2 == vk::TRUE && s.synchronization2 == vk::FALSE {
624                return false;
625            }
626            if r.texture_compression_astc_hdr == vk::TRUE
627                && s.texture_compression_astc_hdr == vk::FALSE
628            {
629                return false;
630            }
631            if r.shader_zero_initialize_workgroup_memory == vk::TRUE
632                && s.shader_zero_initialize_workgroup_memory == vk::FALSE
633            {
634                return false;
635            }
636            if r.dynamic_rendering == vk::TRUE && s.dynamic_rendering == vk::FALSE {
637                return false;
638            }
639            if r.shader_integer_dot_product == vk::TRUE && s.shader_integer_dot_product == vk::FALSE
640            {
641                return false;
642            }
643            if r.maintenance4 == vk::TRUE && s.maintenance4 == vk::FALSE {
644                return false;
645            }
646            true
647        }
648        _ => unsafe { unreachable_unchecked() },
649    }
650}
651impl<'a> VulkanPhysicalDeviceFeature2 {
652    fn combine(&mut self, other: &VulkanPhysicalDeviceFeature2) {
653        assert_eq!(self.s_type(), other.s_type());
654
655        match (self, other) {
656            (
657                Self::PhysicalDeviceVulkan11(f),
658                VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(other),
659            ) => {
660                f.storage_buffer_16bit_access |= other.storage_buffer_16bit_access;
661                f.uniform_and_storage_buffer_16bit_access |=
662                    other.uniform_and_storage_buffer_16bit_access;
663                f.storage_push_constant16 |= other.storage_push_constant16;
664                f.storage_input_output16 |= other.storage_input_output16;
665                f.multiview |= other.multiview;
666                f.multiview_geometry_shader |= other.multiview_geometry_shader;
667                f.multiview_tessellation_shader |= other.multiview_tessellation_shader;
668                f.variable_pointers_storage_buffer |= other.variable_pointers_storage_buffer;
669                f.variable_pointers |= other.variable_pointers;
670                f.protected_memory |= other.protected_memory;
671                f.sampler_ycbcr_conversion |= other.sampler_ycbcr_conversion;
672                f.shader_draw_parameters |= other.shader_draw_parameters;
673            }
674            (
675                Self::PhysicalDeviceVulkan12(f),
676                VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(other),
677            ) => {
678                f.sampler_mirror_clamp_to_edge |= other.sampler_mirror_clamp_to_edge;
679                f.draw_indirect_count |= other.draw_indirect_count;
680                f.storage_buffer_8bit_access |= other.storage_buffer_8bit_access;
681                f.uniform_and_storage_buffer_8bit_access |=
682                    other.uniform_and_storage_buffer_8bit_access;
683                f.storage_push_constant8 |= other.storage_push_constant8;
684                f.shader_buffer_int64_atomics |= other.shader_buffer_int64_atomics;
685                f.shader_shared_int64_atomics |= other.shader_shared_int64_atomics;
686                f.shader_float16 |= other.shader_float16;
687                f.shader_int8 |= other.shader_int8;
688                f.descriptor_indexing |= other.descriptor_indexing;
689                f.shader_input_attachment_array_dynamic_indexing |=
690                    other.shader_input_attachment_array_dynamic_indexing;
691                f.shader_uniform_texel_buffer_array_dynamic_indexing |=
692                    other.shader_uniform_texel_buffer_array_dynamic_indexing;
693                f.shader_storage_texel_buffer_array_dynamic_indexing |=
694                    other.shader_storage_texel_buffer_array_dynamic_indexing;
695                f.shader_uniform_buffer_array_non_uniform_indexing |=
696                    other.shader_uniform_buffer_array_non_uniform_indexing;
697                f.shader_sampled_image_array_non_uniform_indexing |=
698                    other.shader_sampled_image_array_non_uniform_indexing;
699                f.shader_storage_buffer_array_non_uniform_indexing |=
700                    other.shader_storage_buffer_array_non_uniform_indexing;
701                f.shader_storage_image_array_non_uniform_indexing |=
702                    other.shader_storage_image_array_non_uniform_indexing;
703                f.shader_input_attachment_array_non_uniform_indexing |=
704                    other.shader_input_attachment_array_non_uniform_indexing;
705                f.shader_uniform_texel_buffer_array_non_uniform_indexing |=
706                    other.shader_uniform_texel_buffer_array_non_uniform_indexing;
707                f.shader_storage_texel_buffer_array_non_uniform_indexing |=
708                    other.shader_storage_texel_buffer_array_non_uniform_indexing;
709                f.descriptor_binding_uniform_buffer_update_after_bind |=
710                    other.descriptor_binding_uniform_buffer_update_after_bind;
711                f.descriptor_binding_sampled_image_update_after_bind |=
712                    other.descriptor_binding_sampled_image_update_after_bind;
713                f.descriptor_binding_storage_image_update_after_bind |=
714                    other.descriptor_binding_storage_image_update_after_bind;
715                f.descriptor_binding_storage_buffer_update_after_bind |=
716                    other.descriptor_binding_storage_buffer_update_after_bind;
717                f.descriptor_binding_uniform_texel_buffer_update_after_bind |=
718                    other.descriptor_binding_uniform_texel_buffer_update_after_bind;
719                f.descriptor_binding_storage_texel_buffer_update_after_bind |=
720                    other.descriptor_binding_storage_texel_buffer_update_after_bind;
721                f.descriptor_binding_update_unused_while_pending |=
722                    other.descriptor_binding_update_unused_while_pending;
723                f.descriptor_binding_partially_bound |= other.descriptor_binding_partially_bound;
724                f.descriptor_binding_variable_descriptor_count |=
725                    other.descriptor_binding_variable_descriptor_count;
726                f.runtime_descriptor_array |= other.runtime_descriptor_array;
727                f.sampler_filter_minmax |= other.sampler_filter_minmax;
728                f.scalar_block_layout |= other.scalar_block_layout;
729                f.imageless_framebuffer |= other.imageless_framebuffer;
730                f.uniform_buffer_standard_layout |= other.uniform_buffer_standard_layout;
731                f.shader_subgroup_extended_types |= other.shader_subgroup_extended_types;
732                f.separate_depth_stencil_layouts |= other.separate_depth_stencil_layouts;
733                f.host_query_reset |= other.host_query_reset;
734                f.timeline_semaphore |= other.timeline_semaphore;
735                f.buffer_device_address |= other.buffer_device_address;
736                f.buffer_device_address_capture_replay |=
737                    other.buffer_device_address_capture_replay;
738                f.buffer_device_address_multi_device |= other.buffer_device_address_multi_device;
739                f.vulkan_memory_model |= other.vulkan_memory_model;
740                f.vulkan_memory_model_device_scope |= other.vulkan_memory_model_device_scope;
741                f.vulkan_memory_model_availability_visibility_chains |=
742                    other.vulkan_memory_model_availability_visibility_chains;
743                f.shader_output_viewport_index |= other.shader_output_viewport_index;
744                f.shader_output_layer |= other.shader_output_layer;
745                f.subgroup_broadcast_dynamic_id |= other.subgroup_broadcast_dynamic_id;
746            }
747            (
748                Self::PhysicalDeviceVulkan13(f),
749                VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(other),
750            ) => {
751                f.robust_image_access |= other.robust_image_access;
752                f.inline_uniform_block |= other.inline_uniform_block;
753                f.descriptor_binding_inline_uniform_block_update_after_bind |=
754                    other.descriptor_binding_inline_uniform_block_update_after_bind;
755                f.pipeline_creation_cache_control |= other.pipeline_creation_cache_control;
756                f.private_data |= other.private_data;
757                f.shader_demote_to_helper_invocation |= other.shader_demote_to_helper_invocation;
758                f.shader_terminate_invocation |= other.shader_terminate_invocation;
759                f.subgroup_size_control |= other.subgroup_size_control;
760                f.compute_full_subgroups |= other.compute_full_subgroups;
761                f.synchronization2 |= other.synchronization2;
762                f.texture_compression_astc_hdr |= other.texture_compression_astc_hdr;
763                f.shader_zero_initialize_workgroup_memory |=
764                    other.shader_zero_initialize_workgroup_memory;
765                f.dynamic_rendering |= other.dynamic_rendering;
766                f.shader_integer_dot_product |= other.shader_integer_dot_product;
767                f.maintenance4 |= other.maintenance4;
768            }
769            _ => unsafe { unreachable_unchecked() },
770        }
771    }
772
773    fn s_type(&self) -> vk::StructureType {
774        match self {
775            Self::PhysicalDeviceVulkan11(f) => f.s_type,
776            Self::PhysicalDeviceVulkan12(f) => f.s_type,
777            Self::PhysicalDeviceVulkan13(f) => f.s_type,
778        }
779    }
780}
781
782impl From<vk::PhysicalDeviceVulkan11Features> for VulkanPhysicalDeviceFeature2 {
783    fn from(value: vk::PhysicalDeviceVulkan11Features) -> Self {
784        Self::PhysicalDeviceVulkan11(value)
785    }
786}
787
788impl From<vk::PhysicalDeviceVulkan12Features> for VulkanPhysicalDeviceFeature2 {
789    fn from(value: vk::PhysicalDeviceVulkan12Features) -> Self {
790        Self::PhysicalDeviceVulkan12(value)
791    }
792}
793
794impl From<vk::PhysicalDeviceVulkan13Features> for VulkanPhysicalDeviceFeature2 {
795    fn from(value: vk::PhysicalDeviceVulkan13Features) -> Self {
796        Self::PhysicalDeviceVulkan13(value)
797    }
798}
799//endregion vulkanfeatures
800
801#[derive(Debug, Clone, Default)]
802struct GenericFeatureChain {
803    nodes: Vec<VulkanPhysicalDeviceFeature2>,
804}
805
806impl Deref for GenericFeatureChain {
807    type Target = Vec<VulkanPhysicalDeviceFeature2>;
808
809    fn deref(&self) -> &Self::Target {
810        &self.nodes
811    }
812}
813
814impl GenericFeatureChain {
815    fn new() -> Self {
816        Self { nodes: vec![] }
817    }
818
819    fn add(&mut self, feature: impl Into<VulkanPhysicalDeviceFeature2>) {
820        let new_node = feature.into();
821
822        for node in &mut self.nodes {
823            if new_node.s_type() == node.s_type() {
824                node.combine(&new_node);
825                return;
826            }
827        }
828
829        self.nodes.push(new_node);
830    }
831
832    fn match_all(&self, features_requested: &GenericFeatureChain) -> bool {
833        if features_requested.nodes.len() != self.nodes.len() {
834            return false;
835        }
836
837        let features_requested = features_requested.nodes.as_slice();
838        let features = self.nodes.as_slice();
839
840        for (requested_node, node) in features_requested.iter().zip(features) {
841            if !match_features(requested_node, node) {
842                return false;
843            }
844        }
845
846        true
847    }
848}
849
850#[derive(Debug)]
851struct SelectionCriteria {
852    name: String,
853    preferred_device_type: PreferredDeviceType,
854    allow_any_type: bool,
855    require_present: bool,
856    require_dedicated_transfer_queue: bool,
857    require_dedicated_compute_queue: bool,
858    require_separate_transfer_queue: bool,
859    require_separate_compute_queue: bool,
860    required_mem_size: vk::DeviceSize,
861    required_extensions: BTreeSet<vk::ExtensionName>,
862    required_version: Version,
863    required_features: vk::PhysicalDeviceFeatures,
864    required_formats: Vec<vk::Format>,
865    requested_features_chain: RefCell<GenericFeatureChain>,
866    defer_surface_initialization: bool,
867    use_first_gpu_unconditionally: bool,
868    enable_portability_subset: bool,
869}
870
871impl Default for SelectionCriteria {
872    fn default() -> Self {
873        Self {
874            name: String::new(),
875            preferred_device_type: PreferredDeviceType::Discrete,
876            allow_any_type: true,
877            require_present: true,
878            require_dedicated_transfer_queue: false,
879            require_dedicated_compute_queue: false,
880            require_separate_transfer_queue: false,
881            require_separate_compute_queue: false,
882            required_mem_size: 0,
883            required_extensions: BTreeSet::new(),
884            required_version: Version::V1_0_0,
885            required_features: vk::PhysicalDeviceFeatures::default(),
886            defer_surface_initialization: false,
887            use_first_gpu_unconditionally: false,
888            enable_portability_subset: true,
889            requested_features_chain: RefCell::new(GenericFeatureChain::new()),
890            required_formats: vec![],
891        }
892    }
893}
894
895pub struct PhysicalDeviceSelector {
896    instance: Arc<Instance>,
897    surface: Option<vk::SurfaceKHR>,
898    selection_criteria: SelectionCriteria,
899}
900
901impl PhysicalDeviceSelector {
902    pub fn new(instance: Arc<Instance>) -> PhysicalDeviceSelector {
903        let enable_portability_subset = cfg!(feature = "portability");
904        let require_present = instance.surface.is_some();
905        let required_version = instance.api_version;
906        Self {
907            surface: instance.surface,
908            instance,
909            selection_criteria: SelectionCriteria {
910                require_present,
911                required_version,
912                enable_portability_subset,
913                ..Default::default()
914            },
915        }
916    }
917
918    pub fn surface(mut self, surface: vk::SurfaceKHR) -> Self {
919        self.surface.replace(surface);
920        self
921    }
922
923    pub fn add_required_extension_feature<T: Into<VulkanPhysicalDeviceFeature2>>(
924        self,
925        feature: T,
926    ) -> Self {
927        self.selection_criteria
928            .requested_features_chain
929            .borrow_mut()
930            .add(feature);
931        self
932    }
933
934    pub fn add_required_features(mut self, features: vk::PhysicalDeviceFeatures) -> Self {
935        self.selection_criteria.required_features = features;
936        self
937    }
938
939    pub fn name(mut self, name: impl Into<String>) -> Self {
940        self.selection_criteria.name = name.into();
941        self
942    }
943
944    pub fn preferred_device_type(mut self, device_type: PreferredDeviceType) -> Self {
945        self.selection_criteria.preferred_device_type = device_type;
946        self
947    }
948
949    pub fn allow_any_gpu_device_type(mut self, allow: bool) -> Self {
950        self.selection_criteria.allow_any_type = allow;
951        self
952    }
953
954    pub fn require_dedicated_transfer_queue(mut self, require: bool) -> Self {
955        self.selection_criteria.require_dedicated_transfer_queue = require;
956        self
957    }
958
959    pub fn require_dedicated_compute_queue(mut self, require: bool) -> Self {
960        self.selection_criteria.require_dedicated_compute_queue = require;
961        self
962    }
963
964    pub fn require_separate_transfer_queue(mut self, require: bool) -> Self {
965        self.selection_criteria.require_separate_transfer_queue = require;
966        self
967    }
968
969    pub fn require_separate_compute_queue(mut self, require: bool) -> Self {
970        self.selection_criteria.require_separate_compute_queue = require;
971        self
972    }
973
974    pub fn required_device_memory_size(mut self, required: vk::DeviceSize) -> Self {
975        self.selection_criteria.required_mem_size = required;
976        self
977    }
978
979    pub fn required_formats(mut self, required: impl IntoIterator<Item = vk::Format>) -> Self {
980        self.selection_criteria.required_formats = required.into_iter().collect();
981        self
982    }
983
984    pub fn select_first_device_unconditionally(mut self, select: bool) -> Self {
985        self.selection_criteria.use_first_gpu_unconditionally = select;
986        self
987    }
988
989    fn set_is_suitable(&self, device: &mut PhysicalDevice) {
990        let criteria = &self.selection_criteria;
991
992        let device_name = device.properties.device_name.to_string_lossy();
993
994        if !criteria.name.is_empty() && Cow::Borrowed(&criteria.name) != device_name {
995            #[cfg(feature = "enable_tracing")]
996            {
997                tracing::warn!(
998                    "Device {} is not suitable. Name requested: {}",
999                    device_name,
1000                    criteria.name
1001                );
1002            }
1003            device.suitable = Suitable::No;
1004            return;
1005        };
1006
1007        println!(
1008            "req: {}, req u32: {}, api: {}, api u32: {}",
1009            criteria.required_version,
1010            u32::from(criteria.required_version),
1011            Version::from(device.properties.api_version),
1012            device.properties.api_version,
1013        );
1014        if u32::from(criteria.required_version) > device.properties.api_version {
1015            #[cfg(feature = "enable_tracing")]
1016            {
1017                let requested_version = criteria.required_version;
1018                let available_version = device.properties.api_version;
1019                tracing::warn!(
1020                    "Device {} is not suitable. Requested version: {}, Available version: {}",
1021                    device_name,
1022                    requested_version,
1023                    available_version
1024                );
1025            }
1026            device.suitable = Suitable::No;
1027            return;
1028        }
1029
1030        let dedicated_compute = get_dedicated_queue_index(
1031            &device.queue_families,
1032            vk::QueueFlags::COMPUTE,
1033            vk::QueueFlags::TRANSFER,
1034        );
1035
1036        let dedicated_transfer = get_dedicated_queue_index(
1037            &device.queue_families,
1038            vk::QueueFlags::TRANSFER,
1039            vk::QueueFlags::COMPUTE,
1040        );
1041
1042        let separate_compute = get_separate_queue_index(
1043            &device.queue_families,
1044            vk::QueueFlags::COMPUTE,
1045            vk::QueueFlags::TRANSFER,
1046        );
1047
1048        let separate_transfer = get_separate_queue_index(
1049            &device.queue_families,
1050            vk::QueueFlags::TRANSFER,
1051            vk::QueueFlags::COMPUTE,
1052        );
1053
1054        let present_queue = get_present_queue_index(
1055            &self.instance.instance,
1056            device.physical_device,
1057            self.surface,
1058            &device.queue_families,
1059        );
1060
1061        if criteria.require_dedicated_compute_queue && dedicated_compute.is_none() {
1062            device.suitable = Suitable::No;
1063            return;
1064        }
1065
1066        if criteria.require_dedicated_transfer_queue && dedicated_transfer.is_none() {
1067            device.suitable = Suitable::No;
1068            return;
1069        }
1070
1071        if criteria.require_separate_transfer_queue && separate_transfer.is_none() {
1072            device.suitable = Suitable::No;
1073            return;
1074        }
1075
1076        if criteria.require_separate_compute_queue && separate_compute.is_none() {
1077            device.suitable = Suitable::No;
1078            return;
1079        }
1080
1081        if criteria.require_present
1082            && present_queue.is_none()
1083            && !criteria.defer_surface_initialization
1084        {
1085            device.suitable = Suitable::No;
1086            return;
1087        }
1088
1089        let required_extensions_supported = check_device_extension_support(
1090            &device.available_extensions,
1091            &criteria.required_extensions,
1092        );
1093
1094        if required_extensions_supported.len() != criteria.required_extensions.len() {
1095            device.suitable = Suitable::No;
1096            return;
1097        }
1098
1099        if !criteria.defer_surface_initialization && criteria.require_present {
1100            if let Some(surface) = self.surface {
1101                let formats = unsafe {
1102                    self.instance
1103                        .instance
1104                        .get_physical_device_surface_formats_khr(device.physical_device, surface)
1105                };
1106                let Ok(formats) = formats else {
1107                    device.suitable = Suitable::No;
1108                    return;
1109                };
1110
1111                let present_modes = unsafe {
1112                    self.instance
1113                        .instance
1114                        .get_physical_device_surface_present_modes_khr(
1115                            device.physical_device,
1116                            surface,
1117                        )
1118                };
1119                let Ok(present_modes) = present_modes else {
1120                    device.suitable = Suitable::No;
1121                    return;
1122                };
1123
1124                if present_modes.is_empty() || formats.is_empty() {
1125                    device.suitable = Suitable::No;
1126                    return;
1127                }
1128            };
1129        };
1130
1131        let preferred_device_type =
1132            vk::PhysicalDeviceType::from_raw(criteria.preferred_device_type as u8 as i32);
1133        if !criteria.allow_any_type && device.properties.device_type != preferred_device_type {
1134            device.suitable = Suitable::Partial;
1135        }
1136
1137        let required_features_supported = supports_features(
1138            &device.features,
1139            &criteria.required_features,
1140            &device.supported_features_chain,
1141            &criteria.requested_features_chain.borrow(),
1142        );
1143
1144        if !required_features_supported {
1145            device.suitable = Suitable::No;
1146            return;
1147        }
1148
1149        //let supported_formats = &device.format_properties;
1150
1151        for memory_heap in device.memory_properties.memory_heaps {
1152            if memory_heap
1153                .flags
1154                .contains(vk::MemoryHeapFlags::DEVICE_LOCAL)
1155                && memory_heap.size < criteria.required_mem_size
1156            {
1157                device.suitable = Suitable::No;
1158                return;
1159            }
1160        }
1161    }
1162
1163    fn populate_device_details(
1164        &self,
1165        vk_phys_device: vk::PhysicalDevice,
1166    ) -> crate::Result<PhysicalDevice> {
1167        let instance = self.instance.as_ref();
1168        let criteria = &self.selection_criteria;
1169
1170        let mut physical_device = PhysicalDevice {
1171            physical_device: vk_phys_device,
1172            surface: instance.surface,
1173            defer_surface_initialization: criteria.defer_surface_initialization,
1174            queue_families: unsafe {
1175                instance
1176                    .instance
1177                    .get_physical_device_queue_family_properties(vk_phys_device)
1178            },
1179            properties: unsafe {
1180                instance
1181                    .instance
1182                    .get_physical_device_properties(vk_phys_device)
1183            },
1184            features: unsafe {
1185                instance
1186                    .instance
1187                    .get_physical_device_features(vk_phys_device)
1188            },
1189            memory_properties: unsafe {
1190                instance
1191                    .instance
1192                    .get_physical_device_memory_properties(vk_phys_device)
1193            },
1194            // supported_format_properties: {
1195            //     // vulkan has 185 formats in ash
1196            //     let range = 0..185;
1197            //     range
1198            //         .filter_map(|format| {
1199            //             let format = vk::Format::from_raw(format);
1200            //             let format_properties = unsafe {
1201            //                 instance
1202            //                     .instance
1203            //                     .get_physical_device_format_properties(vk_phys_device, format)
1204            //             };
1205            //             if !format_properties.optimal_tiling_features.is_empty()
1206            //                 || !format_properties.buffer_features.is_empty()
1207            //                 || !format_properties.linear_tiling_features.is_empty()
1208            //             {
1209            //                 Some((format, format_properties))
1210            //             } else {
1211            //                 None
1212            //             }
1213            //         })
1214            //         .collect()
1215            // },
1216            properties2_ext_enabled: instance.properties2_ext_enabled,
1217            requested_features_chain: criteria.requested_features_chain.clone().into_inner(),
1218            ..Default::default()
1219        };
1220
1221        physical_device.name = physical_device.properties.clone().device_name.to_string();
1222
1223        let available_extensions = unsafe {
1224            instance
1225                .instance
1226                .enumerate_device_extension_properties(vk_phys_device, None)
1227        };
1228
1229        let Ok(available_extensions) = available_extensions else {
1230            return Ok(physical_device);
1231        };
1232
1233        let available_extensions_names = available_extensions
1234            .into_iter()
1235            .map(|e| e.extension_name)
1236            .collect::<BTreeSet<_>>();
1237
1238        physical_device
1239            .available_extensions
1240            .extend(available_extensions_names);
1241
1242        physical_device.properties2_ext_enabled = instance.properties2_ext_enabled;
1243
1244        let requested_features_chain = criteria.requested_features_chain.borrow();
1245        let instance_is_11 = instance.instance_version >= Version::V1_1_0;
1246        if !requested_features_chain.is_empty()
1247            && (instance_is_11 || instance.properties2_ext_enabled)
1248        {
1249            let mut supported_features = requested_features_chain.clone();
1250            let mut local_features = vk::PhysicalDeviceFeatures2::builder();
1251
1252            for node in supported_features.nodes.iter_mut() {
1253                match node {
1254                    VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(features) => {
1255                        local_features.push_next(features)
1256                    }
1257                    VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(features) => {
1258                        local_features.push_next(features)
1259                    }
1260                    VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(features) => {
1261                        local_features.push_next(features)
1262                    }
1263                };
1264            }
1265
1266            unsafe {
1267                instance.instance.get_physical_device_features2(
1268                    physical_device.physical_device,
1269                    &mut local_features,
1270                )
1271            };
1272
1273            physical_device.supported_features_chain = supported_features.clone();
1274        }
1275
1276        Ok(physical_device)
1277    }
1278
1279    fn select_devices(&self) -> crate::Result<BTreeSet<PhysicalDevice>> {
1280        let criteria = &self.selection_criteria;
1281        dbg!(criteria);
1282        let instance = self.instance.as_ref();
1283        if criteria.require_present
1284            && !criteria.defer_surface_initialization
1285            && instance.surface.is_none()
1286        {
1287            return Err(crate::PhysicalDeviceError::NoSurfaceProvided.into());
1288        };
1289
1290        let physical_devices = unsafe { instance.instance.enumerate_physical_devices() }
1291            .map_err(|_| crate::PhysicalDeviceError::FailedToEnumeratePhysicalDevices)?;
1292        if physical_devices.is_empty() {
1293            return Err(crate::PhysicalDeviceError::NoPhysicalDevicesFound.into());
1294        };
1295
1296        let fill_out_phys_dev_with_criteria = |physical_device: &mut PhysicalDevice| {
1297            physical_device.features = criteria.required_features;
1298            let mut portability_ext_available = false;
1299            let portability_name = vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name;
1300            for ext in &physical_device.available_extensions {
1301                if criteria.enable_portability_subset && ext == &portability_name {
1302                    portability_ext_available = true;
1303                }
1304            }
1305
1306            physical_device.extensions_to_enable.clear();
1307            physical_device
1308                .extensions_to_enable
1309                .extend(criteria.required_extensions.clone());
1310
1311            if portability_ext_available {
1312                physical_device
1313                    .extensions_to_enable
1314                    .insert(portability_name);
1315            }
1316        };
1317
1318        if criteria.use_first_gpu_unconditionally {
1319            let mut device = self.populate_device_details(physical_devices[0])?;
1320            fill_out_phys_dev_with_criteria(&mut device);
1321            return Ok(BTreeSet::from([device]));
1322        };
1323
1324        let physical_devices = physical_devices
1325            .into_iter()
1326            .filter_map(|p| {
1327                let mut phys_dev = self.populate_device_details(p).ok();
1328
1329                if let Some(phys_dev) = phys_dev.as_mut() {
1330                    self.set_is_suitable(phys_dev);
1331                }
1332
1333                phys_dev.and_then(|mut phys_dev| {
1334                    if phys_dev.suitable == Suitable::No {
1335                        None
1336                    } else {
1337                        fill_out_phys_dev_with_criteria(&mut phys_dev);
1338
1339                        Some(phys_dev)
1340                    }
1341                })
1342            })
1343            .collect::<BTreeSet<_>>();
1344
1345        Ok(physical_devices)
1346    }
1347
1348    pub fn select(self) -> crate::Result<PhysicalDevice> {
1349        let devices = self.select_devices()?;
1350        #[cfg(feature = "enable_tracing")]
1351        {
1352            tracing::debug!(
1353                "Device suitability: {:#?}",
1354                devices
1355                    .iter()
1356                    .map(|d| (&d.name, &d.suitable))
1357                    .collect::<Vec<_>>()
1358            );
1359        }
1360
1361        if devices.is_empty() {
1362            Err(crate::PhysicalDeviceError::NoSuitableDevice.into())
1363        } else {
1364            Ok(unsafe { devices.into_iter().next().unwrap_unchecked() })
1365        }
1366    }
1367}
1368
1369pub struct DeviceBuilder {
1370    instance: Arc<Instance>,
1371    physical_device: PhysicalDevice,
1372    allocation_callbacks: Option<AllocationCallbacks>,
1373    // TODO: pNext chains for features
1374    // TODO: queue descriptions
1375}
1376
1377impl DeviceBuilder {
1378    pub fn new(physical_device: PhysicalDevice, instance: Arc<Instance>) -> DeviceBuilder {
1379        Self {
1380            physical_device,
1381            allocation_callbacks: None,
1382            instance,
1383        }
1384    }
1385
1386    pub fn allocation_callbacks(mut self, allocation_callbacks: AllocationCallbacks) -> Self {
1387        self.allocation_callbacks.replace(allocation_callbacks);
1388        self
1389    }
1390
1391    pub fn build(mut self) -> crate::Result<Device> {
1392        // TODO: custom queue setup
1393        // (index, priorities)
1394        let queue_descriptions = self
1395            .physical_device
1396            .queue_families
1397            .iter()
1398            .enumerate()
1399            .map(|(index, _)| (index, [1.]))
1400            .collect::<Vec<_>>();
1401
1402        let queue_create_infos = queue_descriptions
1403            .iter()
1404            .map(|(index, priorities)| {
1405                vk::DeviceQueueCreateInfo::builder()
1406                    .queue_family_index(*index as u32)
1407                    .queue_priorities(priorities)
1408            })
1409            .collect::<Vec<_>>();
1410
1411        let mut extensions_to_enable = self
1412            .physical_device
1413            .extensions_to_enable
1414            .iter()
1415            .map(|ext| ext.as_ptr())
1416            .collect::<Vec<_>>();
1417
1418        if self.physical_device.surface.is_some()
1419            || self.physical_device.defer_surface_initialization
1420        {
1421            extensions_to_enable.push(vk::KHR_SWAPCHAIN_EXTENSION.name.as_ptr());
1422        }
1423
1424        let mut device_create_info = vk::DeviceCreateInfo::builder()
1425            .queue_create_infos(&queue_create_infos)
1426            .enabled_extension_names(&extensions_to_enable);
1427
1428        let requested_features_chain = &mut self.physical_device.requested_features_chain;
1429
1430        let mut features2 =
1431            vk::PhysicalDeviceFeatures2::builder().features(self.physical_device.features);
1432
1433        if self.instance.instance_version >= Version::V1_1_0
1434            || self.physical_device.properties2_ext_enabled
1435        {
1436            device_create_info = device_create_info.push_next(&mut features2);
1437
1438            for node in requested_features_chain.nodes.iter_mut() {
1439                match node {
1440                    VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(f) => {
1441                        device_create_info = device_create_info.push_next(f)
1442                    }
1443                    VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(f) => {
1444                        device_create_info = device_create_info.push_next(f)
1445                    }
1446                    VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(f) => {
1447                        device_create_info = device_create_info.push_next(f)
1448                    }
1449                }
1450            }
1451        }
1452
1453        let device = unsafe {
1454            self.instance.instance.create_device(
1455                self.physical_device.physical_device,
1456                &device_create_info,
1457                self.allocation_callbacks.as_ref(),
1458            )
1459        }?;
1460
1461        let instance = self.instance;
1462        let physical_device = self.physical_device;
1463
1464        let surface = physical_device.surface;
1465        let allocation_callbacks = self.allocation_callbacks;
1466
1467        Ok(Device {
1468            instance,
1469            device,
1470            surface,
1471            physical_device,
1472            allocation_callbacks,
1473        })
1474    }
1475}
1476
1477pub struct Device {
1478    instance: Arc<Instance>,
1479    device: vulkanalia::Device,
1480    physical_device: PhysicalDevice,
1481    surface: Option<vk::SurfaceKHR>,
1482    allocation_callbacks: Option<AllocationCallbacks>,
1483}
1484
1485#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1486pub enum QueueType {
1487    Present,
1488    Graphics,
1489    Compute,
1490    Transfer,
1491}
1492
1493impl Device {
1494    pub fn device(&self) -> &vulkanalia::Device {
1495        &self.device
1496    }
1497
1498    pub fn physical_device(&self) -> &PhysicalDevice {
1499        &self.physical_device
1500    }
1501
1502    pub fn get_queue(&self, queue: QueueType) -> crate::Result<(usize, vk::Queue)> {
1503        let index = match queue {
1504            QueueType::Present => get_present_queue_index(
1505                &self.instance.instance,
1506                self.physical_device.physical_device,
1507                self.surface,
1508                &self.physical_device.queue_families,
1509            )
1510            .ok_or(crate::QueueError::PresentUnavailable),
1511            QueueType::Graphics => get_first_queue_index(
1512                &self.physical_device.queue_families,
1513                vk::QueueFlags::GRAPHICS,
1514            )
1515            .ok_or(crate::QueueError::GraphicsUnavailable),
1516            QueueType::Compute => get_separate_queue_index(
1517                &self.physical_device.queue_families,
1518                vk::QueueFlags::COMPUTE,
1519                vk::QueueFlags::TRANSFER,
1520            )
1521            .ok_or(crate::QueueError::ComputeUnavailable),
1522            QueueType::Transfer => get_separate_queue_index(
1523                &self.physical_device.queue_families,
1524                vk::QueueFlags::TRANSFER,
1525                vk::QueueFlags::COMPUTE,
1526            )
1527            .ok_or(crate::QueueError::TransferUnavailable),
1528        }?;
1529
1530        Ok((index, unsafe {
1531            self.device.get_device_queue(index as _, 0)
1532        }))
1533    }
1534
1535    pub fn get_dedicated_queue(&self, queue: QueueType) -> crate::Result<vk::Queue> {
1536        let index = match queue {
1537            QueueType::Compute => get_dedicated_queue_index(
1538                &self.physical_device.queue_families,
1539                vk::QueueFlags::COMPUTE,
1540                vk::QueueFlags::TRANSFER,
1541            )
1542            .ok_or(crate::QueueError::ComputeUnavailable),
1543            QueueType::Transfer => get_dedicated_queue_index(
1544                &self.physical_device.queue_families,
1545                vk::QueueFlags::TRANSFER,
1546                vk::QueueFlags::COMPUTE,
1547            )
1548            .ok_or(crate::QueueError::TransferUnavailable),
1549            _ => return Err(crate::QueueError::InvalidQueueFamilyIndex.into()),
1550        }?;
1551
1552        let info = vk::DeviceQueueInfo2::builder()
1553            .queue_family_index(index as _)
1554            .queue_index(0);
1555
1556        Ok(unsafe { self.device.get_device_queue2(&info) })
1557    }
1558
1559    pub fn destroy(&self) {
1560        unsafe {
1561            self.device
1562                .destroy_device(self.allocation_callbacks.as_ref());
1563        }
1564    }
1565}
1566
1567impl AsRef<vulkanalia::Device> for Device {
1568    fn as_ref(&self) -> &vulkanalia::Device {
1569        &self.device
1570    }
1571}
1572
1573impl Deref for Device {
1574    type Target = vulkanalia::Device;
1575
1576    fn deref(&self) -> &Self::Target {
1577        &self.device
1578    }
1579}