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, KhrSurfaceExtensionInstanceCommands,
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
99fn 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
123fn 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 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
277 pub fn enable_extension_if_present(&mut self, extension: vk::ExtensionName) -> bool {
281 let extension = extension.into();
282
283 if self.available_extensions.contains(&extension) {
284 self.extensions_to_enable.insert(extension)
285 } else {
286 false
287 }
288 }
289
290 pub fn enable_extensions_if_present<I: IntoIterator<Item = vk::ExtensionName>>(
294 &mut self,
295 extensions: I,
296 ) -> bool {
297 let extensions = BTreeSet::from_iter(extensions);
298 let intersection: BTreeSet<_> = self
299 .available_extensions
300 .intersection(&extensions)
301 .cloned()
302 .collect();
303
304 if intersection.len() == extensions.len() {
305 self.extensions_to_enable.extend(intersection);
306 true
307 } else {
308 false
309 }
310 }
311
312 pub fn name(&self) -> &str {
313 &self.name
314 }
315
316 pub fn api_version(&self) -> u32 {
317 self.properties.api_version
318 }
319
320 pub fn api_version_string(&self) -> String {
321 let major = vk::version_major(self.properties.api_version);
322 let minor = vk::version_minor(self.properties.api_version);
323 let patch = vk::version_patch(self.properties.api_version);
324 format!("{major}.{minor}.{patch}")
325 }
326}
327
328#[derive(Debug, Clone)]
329pub enum VulkanPhysicalDeviceFeature2 {
330 PhysicalDeviceVulkan11(vk::PhysicalDeviceVulkan11Features),
331 PhysicalDeviceVulkan12(vk::PhysicalDeviceVulkan12Features),
332 PhysicalDeviceVulkan13(vk::PhysicalDeviceVulkan13Features),
333}
334
335fn match_features(
336 requested: &VulkanPhysicalDeviceFeature2,
337 supported: &VulkanPhysicalDeviceFeature2,
338) -> bool {
339 assert_eq!(requested.s_type(), supported.s_type());
340
341 match (requested, supported) {
342 (
343 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(r),
344 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(s),
345 ) => {
346 if r.storage_buffer_16bit_access == vk::TRUE
347 && s.storage_buffer_16bit_access == vk::FALSE
348 {
349 return false;
350 }
351 if r.uniform_and_storage_buffer_16bit_access == vk::TRUE
352 && s.uniform_and_storage_buffer_16bit_access == vk::FALSE
353 {
354 return false;
355 }
356 if r.storage_push_constant16 == vk::TRUE && s.storage_push_constant16 == vk::FALSE {
357 return false;
358 }
359 if r.storage_input_output16 == vk::TRUE && s.storage_input_output16 == vk::FALSE {
360 return false;
361 }
362 if r.multiview == vk::TRUE && s.multiview == vk::FALSE {
363 return false;
364 }
365 if r.multiview_geometry_shader == vk::TRUE && s.multiview_geometry_shader == vk::FALSE {
366 return false;
367 }
368 if r.multiview_tessellation_shader == vk::TRUE
369 && s.multiview_tessellation_shader == vk::FALSE
370 {
371 return false;
372 }
373 if r.variable_pointers_storage_buffer == vk::TRUE
374 && s.variable_pointers_storage_buffer == vk::FALSE
375 {
376 return false;
377 }
378 if r.variable_pointers == vk::TRUE && s.variable_pointers == vk::FALSE {
379 return false;
380 }
381 if r.protected_memory == vk::TRUE && s.protected_memory == vk::FALSE {
382 return false;
383 }
384 if r.sampler_ycbcr_conversion == vk::TRUE && s.sampler_ycbcr_conversion == vk::FALSE {
385 return false;
386 }
387 if r.shader_draw_parameters == vk::TRUE && s.shader_draw_parameters == vk::FALSE {
388 return false;
389 }
390 true
391 }
392 (
393 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(r),
394 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(s),
395 ) => {
396 if r.sampler_mirror_clamp_to_edge == vk::TRUE
397 && s.sampler_mirror_clamp_to_edge == vk::FALSE
398 {
399 return false;
400 }
401 if r.draw_indirect_count == vk::TRUE && s.draw_indirect_count == vk::FALSE {
402 return false;
403 }
404 if r.storage_buffer_8bit_access == vk::TRUE && s.storage_buffer_8bit_access == vk::FALSE
405 {
406 return false;
407 }
408 if r.uniform_and_storage_buffer_8bit_access == vk::TRUE
409 && s.uniform_and_storage_buffer_8bit_access == vk::FALSE
410 {
411 return false;
412 }
413 if r.storage_push_constant8 == vk::TRUE && s.storage_push_constant8 == vk::FALSE {
414 return false;
415 }
416 if r.shader_buffer_int64_atomics == vk::TRUE
417 && s.shader_buffer_int64_atomics == vk::FALSE
418 {
419 return false;
420 }
421 if r.shader_shared_int64_atomics == vk::TRUE
422 && s.shader_shared_int64_atomics == vk::FALSE
423 {
424 return false;
425 }
426 if r.shader_float16 == vk::TRUE && s.shader_float16 == vk::FALSE {
427 return false;
428 }
429 if r.shader_int8 == vk::TRUE && s.shader_int8 == vk::FALSE {
430 return false;
431 }
432 if r.descriptor_indexing == vk::TRUE && s.descriptor_indexing == vk::FALSE {
433 return false;
434 }
435 if r.shader_input_attachment_array_dynamic_indexing == vk::TRUE
436 && s.shader_input_attachment_array_dynamic_indexing == vk::FALSE
437 {
438 return false;
439 }
440 if r.shader_uniform_texel_buffer_array_dynamic_indexing == vk::TRUE
441 && s.shader_uniform_texel_buffer_array_dynamic_indexing == vk::FALSE
442 {
443 return false;
444 }
445 if r.shader_storage_texel_buffer_array_dynamic_indexing == vk::TRUE
446 && s.shader_storage_texel_buffer_array_dynamic_indexing == vk::FALSE
447 {
448 return false;
449 }
450 if r.shader_uniform_buffer_array_non_uniform_indexing == vk::TRUE
451 && s.shader_uniform_buffer_array_non_uniform_indexing == vk::FALSE
452 {
453 return false;
454 }
455 if r.shader_sampled_image_array_non_uniform_indexing == vk::TRUE
456 && s.shader_sampled_image_array_non_uniform_indexing == vk::FALSE
457 {
458 return false;
459 }
460 if r.shader_storage_buffer_array_non_uniform_indexing == vk::TRUE
461 && s.shader_storage_buffer_array_non_uniform_indexing == vk::FALSE
462 {
463 return false;
464 }
465 if r.shader_storage_image_array_non_uniform_indexing == vk::TRUE
466 && s.shader_storage_image_array_non_uniform_indexing == vk::FALSE
467 {
468 return false;
469 }
470 if r.shader_input_attachment_array_non_uniform_indexing == vk::TRUE
471 && s.shader_input_attachment_array_non_uniform_indexing == vk::FALSE
472 {
473 return false;
474 }
475 if r.shader_uniform_texel_buffer_array_non_uniform_indexing == vk::TRUE
476 && s.shader_uniform_texel_buffer_array_non_uniform_indexing == vk::FALSE
477 {
478 return false;
479 }
480 if r.shader_storage_texel_buffer_array_non_uniform_indexing == vk::TRUE
481 && s.shader_storage_texel_buffer_array_non_uniform_indexing == vk::FALSE
482 {
483 return false;
484 }
485 if r.descriptor_binding_uniform_buffer_update_after_bind == vk::TRUE
486 && s.descriptor_binding_uniform_buffer_update_after_bind == vk::FALSE
487 {
488 return false;
489 }
490 if r.descriptor_binding_sampled_image_update_after_bind == vk::TRUE
491 && s.descriptor_binding_sampled_image_update_after_bind == vk::FALSE
492 {
493 return false;
494 }
495 if r.descriptor_binding_storage_image_update_after_bind == vk::TRUE
496 && s.descriptor_binding_storage_image_update_after_bind == vk::FALSE
497 {
498 return false;
499 }
500 if r.descriptor_binding_storage_buffer_update_after_bind == vk::TRUE
501 && s.descriptor_binding_storage_buffer_update_after_bind == vk::FALSE
502 {
503 return false;
504 }
505 if r.descriptor_binding_uniform_texel_buffer_update_after_bind == vk::TRUE
506 && s.descriptor_binding_uniform_texel_buffer_update_after_bind == vk::FALSE
507 {
508 return false;
509 }
510 if r.descriptor_binding_storage_texel_buffer_update_after_bind == vk::TRUE
511 && s.descriptor_binding_storage_texel_buffer_update_after_bind == vk::FALSE
512 {
513 return false;
514 }
515 if r.descriptor_binding_update_unused_while_pending == vk::TRUE
516 && s.descriptor_binding_update_unused_while_pending == vk::FALSE
517 {
518 return false;
519 }
520 if r.descriptor_binding_partially_bound == vk::TRUE
521 && s.descriptor_binding_partially_bound == vk::FALSE
522 {
523 return false;
524 }
525 if r.descriptor_binding_variable_descriptor_count == vk::TRUE
526 && s.descriptor_binding_variable_descriptor_count == vk::FALSE
527 {
528 return false;
529 }
530 if r.runtime_descriptor_array == vk::TRUE && s.runtime_descriptor_array == vk::FALSE {
531 return false;
532 }
533 if r.sampler_filter_minmax == vk::TRUE && s.sampler_filter_minmax == vk::FALSE {
534 return false;
535 }
536 if r.scalar_block_layout == vk::TRUE && s.scalar_block_layout == vk::FALSE {
537 return false;
538 }
539 if r.imageless_framebuffer == vk::TRUE && s.imageless_framebuffer == vk::FALSE {
540 return false;
541 }
542 if r.uniform_buffer_standard_layout == vk::TRUE
543 && s.uniform_buffer_standard_layout == vk::FALSE
544 {
545 return false;
546 }
547 if r.shader_subgroup_extended_types == vk::TRUE
548 && s.shader_subgroup_extended_types == vk::FALSE
549 {
550 return false;
551 }
552 if r.separate_depth_stencil_layouts == vk::TRUE
553 && s.separate_depth_stencil_layouts == vk::FALSE
554 {
555 return false;
556 }
557 if r.host_query_reset == vk::TRUE && s.host_query_reset == vk::FALSE {
558 return false;
559 }
560 if r.timeline_semaphore == vk::TRUE && s.timeline_semaphore == vk::FALSE {
561 return false;
562 }
563 if r.buffer_device_address == vk::TRUE && s.buffer_device_address == vk::FALSE {
564 return false;
565 }
566 if r.buffer_device_address_capture_replay == vk::TRUE
567 && s.buffer_device_address_capture_replay == vk::FALSE
568 {
569 return false;
570 }
571 if r.buffer_device_address_multi_device == vk::TRUE
572 && s.buffer_device_address_multi_device == vk::FALSE
573 {
574 return false;
575 }
576 if r.vulkan_memory_model == vk::TRUE && s.vulkan_memory_model == vk::FALSE {
577 return false;
578 }
579 if r.vulkan_memory_model_device_scope == vk::TRUE
580 && s.vulkan_memory_model_device_scope == vk::FALSE
581 {
582 return false;
583 }
584 if r.vulkan_memory_model_availability_visibility_chains == vk::TRUE
585 && s.vulkan_memory_model_availability_visibility_chains == vk::FALSE
586 {
587 return false;
588 }
589 if r.shader_output_viewport_index == vk::TRUE
590 && s.shader_output_viewport_index == vk::FALSE
591 {
592 return false;
593 }
594 if r.shader_output_layer == vk::TRUE && s.shader_output_layer == vk::FALSE {
595 return false;
596 }
597 if r.subgroup_broadcast_dynamic_id == vk::TRUE
598 && s.subgroup_broadcast_dynamic_id == vk::FALSE
599 {
600 return false;
601 }
602 true
603 }
604 (
605 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(r),
606 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(s),
607 ) => {
608 if r.robust_image_access == vk::TRUE && s.robust_image_access == vk::FALSE {
609 return false;
610 }
611 if r.inline_uniform_block == vk::TRUE && s.inline_uniform_block == vk::FALSE {
612 return false;
613 }
614 if r.descriptor_binding_inline_uniform_block_update_after_bind == vk::TRUE
615 && s.descriptor_binding_inline_uniform_block_update_after_bind == vk::FALSE
616 {
617 return false;
618 }
619 if r.pipeline_creation_cache_control == vk::TRUE
620 && s.pipeline_creation_cache_control == vk::FALSE
621 {
622 return false;
623 }
624 if r.private_data == vk::TRUE && s.private_data == vk::FALSE {
625 return false;
626 }
627 if r.shader_demote_to_helper_invocation == vk::TRUE
628 && s.shader_demote_to_helper_invocation == vk::FALSE
629 {
630 return false;
631 }
632 if r.shader_terminate_invocation == vk::TRUE
633 && s.shader_terminate_invocation == vk::FALSE
634 {
635 return false;
636 }
637 if r.subgroup_size_control == vk::TRUE && s.subgroup_size_control == vk::FALSE {
638 return false;
639 }
640 if r.compute_full_subgroups == vk::TRUE && s.compute_full_subgroups == vk::FALSE {
641 return false;
642 }
643 if r.synchronization2 == vk::TRUE && s.synchronization2 == vk::FALSE {
644 return false;
645 }
646 if r.texture_compression_astc_hdr == vk::TRUE
647 && s.texture_compression_astc_hdr == vk::FALSE
648 {
649 return false;
650 }
651 if r.shader_zero_initialize_workgroup_memory == vk::TRUE
652 && s.shader_zero_initialize_workgroup_memory == vk::FALSE
653 {
654 return false;
655 }
656 if r.dynamic_rendering == vk::TRUE && s.dynamic_rendering == vk::FALSE {
657 return false;
658 }
659 if r.shader_integer_dot_product == vk::TRUE && s.shader_integer_dot_product == vk::FALSE
660 {
661 return false;
662 }
663 if r.maintenance4 == vk::TRUE && s.maintenance4 == vk::FALSE {
664 return false;
665 }
666 true
667 }
668 _ => unsafe { unreachable_unchecked() },
669 }
670}
671impl<'a> VulkanPhysicalDeviceFeature2 {
672 fn combine(&mut self, other: &VulkanPhysicalDeviceFeature2) {
673 assert_eq!(self.s_type(), other.s_type());
674
675 match (self, other) {
676 (
677 Self::PhysicalDeviceVulkan11(f),
678 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(other),
679 ) => {
680 f.storage_buffer_16bit_access |= other.storage_buffer_16bit_access;
681 f.uniform_and_storage_buffer_16bit_access |=
682 other.uniform_and_storage_buffer_16bit_access;
683 f.storage_push_constant16 |= other.storage_push_constant16;
684 f.storage_input_output16 |= other.storage_input_output16;
685 f.multiview |= other.multiview;
686 f.multiview_geometry_shader |= other.multiview_geometry_shader;
687 f.multiview_tessellation_shader |= other.multiview_tessellation_shader;
688 f.variable_pointers_storage_buffer |= other.variable_pointers_storage_buffer;
689 f.variable_pointers |= other.variable_pointers;
690 f.protected_memory |= other.protected_memory;
691 f.sampler_ycbcr_conversion |= other.sampler_ycbcr_conversion;
692 f.shader_draw_parameters |= other.shader_draw_parameters;
693 }
694 (
695 Self::PhysicalDeviceVulkan12(f),
696 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(other),
697 ) => {
698 f.sampler_mirror_clamp_to_edge |= other.sampler_mirror_clamp_to_edge;
699 f.draw_indirect_count |= other.draw_indirect_count;
700 f.storage_buffer_8bit_access |= other.storage_buffer_8bit_access;
701 f.uniform_and_storage_buffer_8bit_access |=
702 other.uniform_and_storage_buffer_8bit_access;
703 f.storage_push_constant8 |= other.storage_push_constant8;
704 f.shader_buffer_int64_atomics |= other.shader_buffer_int64_atomics;
705 f.shader_shared_int64_atomics |= other.shader_shared_int64_atomics;
706 f.shader_float16 |= other.shader_float16;
707 f.shader_int8 |= other.shader_int8;
708 f.descriptor_indexing |= other.descriptor_indexing;
709 f.shader_input_attachment_array_dynamic_indexing |=
710 other.shader_input_attachment_array_dynamic_indexing;
711 f.shader_uniform_texel_buffer_array_dynamic_indexing |=
712 other.shader_uniform_texel_buffer_array_dynamic_indexing;
713 f.shader_storage_texel_buffer_array_dynamic_indexing |=
714 other.shader_storage_texel_buffer_array_dynamic_indexing;
715 f.shader_uniform_buffer_array_non_uniform_indexing |=
716 other.shader_uniform_buffer_array_non_uniform_indexing;
717 f.shader_sampled_image_array_non_uniform_indexing |=
718 other.shader_sampled_image_array_non_uniform_indexing;
719 f.shader_storage_buffer_array_non_uniform_indexing |=
720 other.shader_storage_buffer_array_non_uniform_indexing;
721 f.shader_storage_image_array_non_uniform_indexing |=
722 other.shader_storage_image_array_non_uniform_indexing;
723 f.shader_input_attachment_array_non_uniform_indexing |=
724 other.shader_input_attachment_array_non_uniform_indexing;
725 f.shader_uniform_texel_buffer_array_non_uniform_indexing |=
726 other.shader_uniform_texel_buffer_array_non_uniform_indexing;
727 f.shader_storage_texel_buffer_array_non_uniform_indexing |=
728 other.shader_storage_texel_buffer_array_non_uniform_indexing;
729 f.descriptor_binding_uniform_buffer_update_after_bind |=
730 other.descriptor_binding_uniform_buffer_update_after_bind;
731 f.descriptor_binding_sampled_image_update_after_bind |=
732 other.descriptor_binding_sampled_image_update_after_bind;
733 f.descriptor_binding_storage_image_update_after_bind |=
734 other.descriptor_binding_storage_image_update_after_bind;
735 f.descriptor_binding_storage_buffer_update_after_bind |=
736 other.descriptor_binding_storage_buffer_update_after_bind;
737 f.descriptor_binding_uniform_texel_buffer_update_after_bind |=
738 other.descriptor_binding_uniform_texel_buffer_update_after_bind;
739 f.descriptor_binding_storage_texel_buffer_update_after_bind |=
740 other.descriptor_binding_storage_texel_buffer_update_after_bind;
741 f.descriptor_binding_update_unused_while_pending |=
742 other.descriptor_binding_update_unused_while_pending;
743 f.descriptor_binding_partially_bound |= other.descriptor_binding_partially_bound;
744 f.descriptor_binding_variable_descriptor_count |=
745 other.descriptor_binding_variable_descriptor_count;
746 f.runtime_descriptor_array |= other.runtime_descriptor_array;
747 f.sampler_filter_minmax |= other.sampler_filter_minmax;
748 f.scalar_block_layout |= other.scalar_block_layout;
749 f.imageless_framebuffer |= other.imageless_framebuffer;
750 f.uniform_buffer_standard_layout |= other.uniform_buffer_standard_layout;
751 f.shader_subgroup_extended_types |= other.shader_subgroup_extended_types;
752 f.separate_depth_stencil_layouts |= other.separate_depth_stencil_layouts;
753 f.host_query_reset |= other.host_query_reset;
754 f.timeline_semaphore |= other.timeline_semaphore;
755 f.buffer_device_address |= other.buffer_device_address;
756 f.buffer_device_address_capture_replay |=
757 other.buffer_device_address_capture_replay;
758 f.buffer_device_address_multi_device |= other.buffer_device_address_multi_device;
759 f.vulkan_memory_model |= other.vulkan_memory_model;
760 f.vulkan_memory_model_device_scope |= other.vulkan_memory_model_device_scope;
761 f.vulkan_memory_model_availability_visibility_chains |=
762 other.vulkan_memory_model_availability_visibility_chains;
763 f.shader_output_viewport_index |= other.shader_output_viewport_index;
764 f.shader_output_layer |= other.shader_output_layer;
765 f.subgroup_broadcast_dynamic_id |= other.subgroup_broadcast_dynamic_id;
766 }
767 (
768 Self::PhysicalDeviceVulkan13(f),
769 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(other),
770 ) => {
771 f.robust_image_access |= other.robust_image_access;
772 f.inline_uniform_block |= other.inline_uniform_block;
773 f.descriptor_binding_inline_uniform_block_update_after_bind |=
774 other.descriptor_binding_inline_uniform_block_update_after_bind;
775 f.pipeline_creation_cache_control |= other.pipeline_creation_cache_control;
776 f.private_data |= other.private_data;
777 f.shader_demote_to_helper_invocation |= other.shader_demote_to_helper_invocation;
778 f.shader_terminate_invocation |= other.shader_terminate_invocation;
779 f.subgroup_size_control |= other.subgroup_size_control;
780 f.compute_full_subgroups |= other.compute_full_subgroups;
781 f.synchronization2 |= other.synchronization2;
782 f.texture_compression_astc_hdr |= other.texture_compression_astc_hdr;
783 f.shader_zero_initialize_workgroup_memory |=
784 other.shader_zero_initialize_workgroup_memory;
785 f.dynamic_rendering |= other.dynamic_rendering;
786 f.shader_integer_dot_product |= other.shader_integer_dot_product;
787 f.maintenance4 |= other.maintenance4;
788 }
789 _ => unsafe { unreachable_unchecked() },
790 }
791 }
792
793 fn s_type(&self) -> vk::StructureType {
794 match self {
795 Self::PhysicalDeviceVulkan11(f) => f.s_type,
796 Self::PhysicalDeviceVulkan12(f) => f.s_type,
797 Self::PhysicalDeviceVulkan13(f) => f.s_type,
798 }
799 }
800}
801
802impl From<vk::PhysicalDeviceVulkan11Features> for VulkanPhysicalDeviceFeature2 {
803 fn from(value: vk::PhysicalDeviceVulkan11Features) -> Self {
804 Self::PhysicalDeviceVulkan11(value)
805 }
806}
807
808impl From<vk::PhysicalDeviceVulkan12Features> for VulkanPhysicalDeviceFeature2 {
809 fn from(value: vk::PhysicalDeviceVulkan12Features) -> Self {
810 Self::PhysicalDeviceVulkan12(value)
811 }
812}
813
814impl From<vk::PhysicalDeviceVulkan13Features> for VulkanPhysicalDeviceFeature2 {
815 fn from(value: vk::PhysicalDeviceVulkan13Features) -> Self {
816 Self::PhysicalDeviceVulkan13(value)
817 }
818}
819#[derive(Debug, Clone, Default)]
822struct GenericFeatureChain {
823 nodes: Vec<VulkanPhysicalDeviceFeature2>,
824}
825
826impl Deref for GenericFeatureChain {
827 type Target = Vec<VulkanPhysicalDeviceFeature2>;
828
829 fn deref(&self) -> &Self::Target {
830 &self.nodes
831 }
832}
833
834impl GenericFeatureChain {
835 fn new() -> Self {
836 Self { nodes: vec![] }
837 }
838
839 fn add(&mut self, feature: impl Into<VulkanPhysicalDeviceFeature2>) {
840 let new_node = feature.into();
841
842 for node in &mut self.nodes {
843 if new_node.s_type() == node.s_type() {
844 node.combine(&new_node);
845 return;
846 }
847 }
848
849 self.nodes.push(new_node);
850 }
851
852 fn match_all(&self, features_requested: &GenericFeatureChain) -> bool {
853 if features_requested.nodes.len() != self.nodes.len() {
854 return false;
855 }
856
857 let features_requested = features_requested.nodes.as_slice();
858 let features = self.nodes.as_slice();
859
860 for (requested_node, node) in features_requested.iter().zip(features) {
861 if !match_features(requested_node, node) {
862 return false;
863 }
864 }
865
866 true
867 }
868}
869
870#[derive(Debug)]
871struct SelectionCriteria {
872 name: String,
873 preferred_device_type: PreferredDeviceType,
874 allow_any_type: bool,
875 require_present: bool,
876 require_dedicated_transfer_queue: bool,
877 require_dedicated_compute_queue: bool,
878 require_separate_transfer_queue: bool,
879 require_separate_compute_queue: bool,
880 required_mem_size: vk::DeviceSize,
881 required_extensions: BTreeSet<vk::ExtensionName>,
882 required_version: Version,
883 required_features: vk::PhysicalDeviceFeatures,
884 required_formats: Vec<vk::Format>,
885 requested_features_chain: RefCell<GenericFeatureChain>,
886 defer_surface_initialization: bool,
887 use_first_gpu_unconditionally: bool,
888 enable_portability_subset: bool,
889}
890
891impl Default for SelectionCriteria {
892 fn default() -> Self {
893 Self {
894 name: String::new(),
895 preferred_device_type: PreferredDeviceType::Discrete,
896 allow_any_type: true,
897 require_present: true,
898 require_dedicated_transfer_queue: false,
899 require_dedicated_compute_queue: false,
900 require_separate_transfer_queue: false,
901 require_separate_compute_queue: false,
902 required_mem_size: 0,
903 required_extensions: BTreeSet::new(),
904 required_version: Version::V1_0_0,
905 required_features: vk::PhysicalDeviceFeatures::default(),
906 defer_surface_initialization: false,
907 use_first_gpu_unconditionally: false,
908 enable_portability_subset: true,
909 requested_features_chain: RefCell::new(GenericFeatureChain::new()),
910 required_formats: vec![],
911 }
912 }
913}
914
915pub struct PhysicalDeviceSelector {
916 instance: Arc<Instance>,
917 surface: Option<vk::SurfaceKHR>,
918 selection_criteria: SelectionCriteria,
919}
920
921impl PhysicalDeviceSelector {
922 pub fn new(instance: Arc<Instance>) -> PhysicalDeviceSelector {
926 let enable_portability_subset = cfg!(feature = "portability");
927 let require_present = instance.surface.is_some();
928 let required_version = instance.api_version;
929 Self {
930 surface: instance.surface,
931 instance,
932 selection_criteria: SelectionCriteria {
933 require_present,
934 required_version,
935 enable_portability_subset,
936 ..Default::default()
937 },
938 }
939 }
940
941 pub fn surface(mut self, surface: vk::SurfaceKHR) -> Self {
943 self.surface.replace(surface);
944 self
945 }
946
947 pub fn add_required_extension_feature<T: Into<VulkanPhysicalDeviceFeature2>>(
950 self,
951 feature: T,
952 ) -> Self {
953 self.selection_criteria
954 .requested_features_chain
955 .borrow_mut()
956 .add(feature);
957 self
958 }
959
960 pub fn add_required_features(mut self, features: vk::PhysicalDeviceFeatures) -> Self {
962 self.selection_criteria.required_features = features;
963 self
964 }
965
966 pub fn name(mut self, name: impl Into<String>) -> Self {
968 self.selection_criteria.name = name.into();
969 self
970 }
971
972 pub fn preferred_device_type(mut self, device_type: PreferredDeviceType) -> Self {
974 self.selection_criteria.preferred_device_type = device_type;
975 self
976 }
977
978 pub fn allow_any_gpu_device_type(mut self, allow: bool) -> Self {
980 self.selection_criteria.allow_any_type = allow;
981 self
982 }
983
984 pub fn require_dedicated_transfer_queue(mut self, require: bool) -> Self {
986 self.selection_criteria.require_dedicated_transfer_queue = require;
987 self
988 }
989
990 pub fn require_dedicated_compute_queue(mut self, require: bool) -> Self {
992 self.selection_criteria.require_dedicated_compute_queue = require;
993 self
994 }
995
996 pub fn require_separate_transfer_queue(mut self, require: bool) -> Self {
998 self.selection_criteria.require_separate_transfer_queue = require;
999 self
1000 }
1001
1002 pub fn require_separate_compute_queue(mut self, require: bool) -> Self {
1004 self.selection_criteria.require_separate_compute_queue = require;
1005 self
1006 }
1007
1008 pub fn required_device_memory_size(mut self, required: vk::DeviceSize) -> Self {
1010 self.selection_criteria.required_mem_size = required;
1011 self
1012 }
1013
1014 pub fn required_formats(mut self, required: impl IntoIterator<Item = vk::Format>) -> Self {
1016 self.selection_criteria.required_formats = required.into_iter().collect();
1017 self
1018 }
1019
1020 pub fn select_first_device_unconditionally(mut self, select: bool) -> Self {
1023 self.selection_criteria.use_first_gpu_unconditionally = select;
1024 self
1025 }
1026
1027 fn set_is_suitable(&self, device: &mut PhysicalDevice) {
1028 let criteria = &self.selection_criteria;
1029
1030 let device_name = device.properties.device_name.to_string_lossy();
1031
1032 if !criteria.name.is_empty() && Cow::Borrowed(&criteria.name) != device_name {
1033 #[cfg(feature = "enable_tracing")]
1034 {
1035 tracing::warn!(
1036 "Device {} is not suitable. Name requested: {}",
1037 device_name,
1038 criteria.name
1039 );
1040 }
1041 device.suitable = Suitable::No;
1042 return;
1043 };
1044
1045 if u32::from(criteria.required_version) > device.properties.api_version {
1046 #[cfg(feature = "enable_tracing")]
1047 {
1048 let requested_version = criteria.required_version;
1049 let available_version = device.properties.api_version;
1050 tracing::warn!(
1051 "Device {} is not suitable. Requested version: {}, Available version: {}",
1052 device_name,
1053 requested_version,
1054 available_version
1055 );
1056 }
1057 device.suitable = Suitable::No;
1058 return;
1059 }
1060
1061 let dedicated_compute = get_dedicated_queue_index(
1062 &device.queue_families,
1063 vk::QueueFlags::COMPUTE,
1064 vk::QueueFlags::TRANSFER,
1065 );
1066
1067 let dedicated_transfer = get_dedicated_queue_index(
1068 &device.queue_families,
1069 vk::QueueFlags::TRANSFER,
1070 vk::QueueFlags::COMPUTE,
1071 );
1072
1073 let separate_compute = get_separate_queue_index(
1074 &device.queue_families,
1075 vk::QueueFlags::COMPUTE,
1076 vk::QueueFlags::TRANSFER,
1077 );
1078
1079 let separate_transfer = get_separate_queue_index(
1080 &device.queue_families,
1081 vk::QueueFlags::TRANSFER,
1082 vk::QueueFlags::COMPUTE,
1083 );
1084
1085 let present_queue = get_present_queue_index(
1086 &self.instance.instance,
1087 device.physical_device,
1088 self.surface,
1089 &device.queue_families,
1090 );
1091
1092 if criteria.require_dedicated_compute_queue && dedicated_compute.is_none() {
1093 device.suitable = Suitable::No;
1094 return;
1095 }
1096
1097 if criteria.require_dedicated_transfer_queue && dedicated_transfer.is_none() {
1098 device.suitable = Suitable::No;
1099 return;
1100 }
1101
1102 if criteria.require_separate_transfer_queue && separate_transfer.is_none() {
1103 device.suitable = Suitable::No;
1104 return;
1105 }
1106
1107 if criteria.require_separate_compute_queue && separate_compute.is_none() {
1108 device.suitable = Suitable::No;
1109 return;
1110 }
1111
1112 if criteria.require_present
1113 && present_queue.is_none()
1114 && !criteria.defer_surface_initialization
1115 {
1116 device.suitable = Suitable::No;
1117 return;
1118 }
1119
1120 let required_extensions_supported = check_device_extension_support(
1121 &device.available_extensions,
1122 &criteria.required_extensions,
1123 );
1124
1125 if required_extensions_supported.len() != criteria.required_extensions.len() {
1126 device.suitable = Suitable::No;
1127 return;
1128 }
1129
1130 if !criteria.defer_surface_initialization && criteria.require_present {
1131 if let Some(surface) = self.surface {
1132 let formats = unsafe {
1133 self.instance
1134 .instance
1135 .get_physical_device_surface_formats_khr(device.physical_device, surface)
1136 };
1137 let Ok(formats) = formats else {
1138 device.suitable = Suitable::No;
1139 return;
1140 };
1141
1142 let present_modes = unsafe {
1143 self.instance
1144 .instance
1145 .get_physical_device_surface_present_modes_khr(
1146 device.physical_device,
1147 surface,
1148 )
1149 };
1150 let Ok(present_modes) = present_modes else {
1151 device.suitable = Suitable::No;
1152 return;
1153 };
1154
1155 if present_modes.is_empty() || formats.is_empty() {
1156 device.suitable = Suitable::No;
1157 return;
1158 }
1159 };
1160 };
1161
1162 let preferred_device_type =
1163 vk::PhysicalDeviceType::from_raw(criteria.preferred_device_type as u8 as i32);
1164 if !criteria.allow_any_type && device.properties.device_type != preferred_device_type {
1165 device.suitable = Suitable::Partial;
1166 }
1167
1168 let required_features_supported = supports_features(
1169 &device.features,
1170 &criteria.required_features,
1171 &device.supported_features_chain,
1172 &criteria.requested_features_chain.borrow(),
1173 );
1174
1175 if !required_features_supported {
1176 device.suitable = Suitable::No;
1177 return;
1178 }
1179
1180 for memory_heap in device.memory_properties.memory_heaps {
1183 if memory_heap
1184 .flags
1185 .contains(vk::MemoryHeapFlags::DEVICE_LOCAL)
1186 && memory_heap.size < criteria.required_mem_size
1187 {
1188 device.suitable = Suitable::No;
1189 return;
1190 }
1191 }
1192 }
1193
1194 fn populate_device_details(
1195 &self,
1196 vk_phys_device: vk::PhysicalDevice,
1197 ) -> crate::Result<PhysicalDevice> {
1198 let instance = self.instance.as_ref();
1199 let criteria = &self.selection_criteria;
1200
1201 let mut physical_device = PhysicalDevice {
1202 physical_device: vk_phys_device,
1203 surface: instance.surface,
1204 defer_surface_initialization: criteria.defer_surface_initialization,
1205 queue_families: unsafe {
1206 instance
1207 .instance
1208 .get_physical_device_queue_family_properties(vk_phys_device)
1209 },
1210 properties: unsafe {
1211 instance
1212 .instance
1213 .get_physical_device_properties(vk_phys_device)
1214 },
1215 features: unsafe {
1216 instance
1217 .instance
1218 .get_physical_device_features(vk_phys_device)
1219 },
1220 memory_properties: unsafe {
1221 instance
1222 .instance
1223 .get_physical_device_memory_properties(vk_phys_device)
1224 },
1225 properties2_ext_enabled: instance.properties2_ext_enabled,
1248 requested_features_chain: criteria.requested_features_chain.clone().into_inner(),
1249 ..Default::default()
1250 };
1251
1252 physical_device.name = physical_device.properties.clone().device_name.to_string();
1253
1254 let available_extensions = unsafe {
1255 instance
1256 .instance
1257 .enumerate_device_extension_properties(vk_phys_device, None)
1258 };
1259
1260 let Ok(available_extensions) = available_extensions else {
1261 return Ok(physical_device);
1262 };
1263
1264 let available_extensions_names = available_extensions
1265 .into_iter()
1266 .map(|e| e.extension_name)
1267 .collect::<BTreeSet<_>>();
1268
1269 physical_device
1270 .available_extensions
1271 .extend(available_extensions_names);
1272
1273 physical_device.properties2_ext_enabled = instance.properties2_ext_enabled;
1274
1275 let requested_features_chain = criteria.requested_features_chain.borrow();
1276 let instance_is_11 = instance.instance_version >= Version::V1_1_0;
1277 if !requested_features_chain.is_empty()
1278 && (instance_is_11 || instance.properties2_ext_enabled)
1279 {
1280 let mut supported_features = requested_features_chain.clone();
1281 let mut local_features = vk::PhysicalDeviceFeatures2::builder();
1282
1283 for node in supported_features.nodes.iter_mut() {
1284 match node {
1285 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(features) => {
1286 local_features.push_next(features)
1287 }
1288 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(features) => {
1289 local_features.push_next(features)
1290 }
1291 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(features) => {
1292 local_features.push_next(features)
1293 }
1294 };
1295 }
1296
1297 unsafe {
1298 instance.instance.get_physical_device_features2(
1299 physical_device.physical_device,
1300 &mut local_features,
1301 )
1302 };
1303
1304 physical_device.supported_features_chain = supported_features.clone();
1305 }
1306
1307 Ok(physical_device)
1308 }
1309
1310 fn select_devices(&self) -> crate::Result<BTreeSet<PhysicalDevice>> {
1311 let criteria = &self.selection_criteria;
1312 let instance = self.instance.as_ref();
1313 if criteria.require_present
1314 && !criteria.defer_surface_initialization
1315 && instance.surface.is_none()
1316 {
1317 return Err(crate::PhysicalDeviceError::NoSurfaceProvided.into());
1318 };
1319
1320 let physical_devices = unsafe { instance.instance.enumerate_physical_devices() }
1321 .map_err(|_| crate::PhysicalDeviceError::FailedToEnumeratePhysicalDevices)?;
1322 if physical_devices.is_empty() {
1323 return Err(crate::PhysicalDeviceError::NoPhysicalDevicesFound.into());
1324 };
1325
1326 let fill_out_phys_dev_with_criteria = |physical_device: &mut PhysicalDevice| {
1327 physical_device.features = criteria.required_features;
1328 let mut portability_ext_available = false;
1329 let portability_name = vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name;
1330 for ext in &physical_device.available_extensions {
1331 if criteria.enable_portability_subset && ext == &portability_name {
1332 portability_ext_available = true;
1333 }
1334 }
1335
1336 physical_device.extensions_to_enable.clear();
1337 physical_device
1338 .extensions_to_enable
1339 .extend(criteria.required_extensions.clone());
1340
1341 if portability_ext_available {
1342 physical_device
1343 .extensions_to_enable
1344 .insert(portability_name);
1345 }
1346 };
1347
1348 if criteria.use_first_gpu_unconditionally {
1349 let mut device = self.populate_device_details(physical_devices[0])?;
1350 fill_out_phys_dev_with_criteria(&mut device);
1351 return Ok(BTreeSet::from([device]));
1352 };
1353
1354 let physical_devices = physical_devices
1355 .into_iter()
1356 .filter_map(|p| {
1357 let mut phys_dev = self.populate_device_details(p).ok();
1358
1359 if let Some(phys_dev) = phys_dev.as_mut() {
1360 self.set_is_suitable(phys_dev);
1361 }
1362
1363 phys_dev.and_then(|mut phys_dev| {
1364 if phys_dev.suitable == Suitable::No {
1365 None
1366 } else {
1367 fill_out_phys_dev_with_criteria(&mut phys_dev);
1368
1369 Some(phys_dev)
1370 }
1371 })
1372 })
1373 .collect::<BTreeSet<_>>();
1374
1375 Ok(physical_devices)
1376 }
1377
1378 pub fn select(self) -> crate::Result<PhysicalDevice> {
1382 let devices = self.select_devices()?;
1383 #[cfg(feature = "enable_tracing")]
1384 {
1385 tracing::debug!(
1386 "Device suitability: {:#?}",
1387 devices
1388 .iter()
1389 .map(|d| (&d.name, &d.suitable))
1390 .collect::<Vec<_>>()
1391 );
1392 }
1393
1394 if devices.is_empty() {
1395 Err(crate::PhysicalDeviceError::NoSuitableDevice.into())
1396 } else {
1397 Ok(unsafe { devices.into_iter().next().unwrap_unchecked() })
1398 }
1399 }
1400}
1401
1402pub struct DeviceBuilder {
1403 instance: Arc<Instance>,
1404 physical_device: PhysicalDevice,
1405 allocation_callbacks: Option<AllocationCallbacks>,
1406 }
1409
1410impl DeviceBuilder {
1411 pub fn new(physical_device: PhysicalDevice, instance: Arc<Instance>) -> DeviceBuilder {
1412 Self {
1413 physical_device,
1414 allocation_callbacks: None,
1415 instance,
1416 }
1417 }
1418
1419 pub fn allocation_callbacks(mut self, allocation_callbacks: AllocationCallbacks) -> Self {
1420 self.allocation_callbacks.replace(allocation_callbacks);
1421 self
1422 }
1423
1424 pub fn build(mut self) -> crate::Result<Device> {
1446 let queue_descriptions = self
1449 .physical_device
1450 .queue_families
1451 .iter()
1452 .enumerate()
1453 .map(|(index, _)| (index, [1.]))
1454 .collect::<Vec<_>>();
1455
1456 let queue_create_infos = queue_descriptions
1457 .iter()
1458 .map(|(index, priorities)| {
1459 vk::DeviceQueueCreateInfo::builder()
1460 .queue_family_index(*index as u32)
1461 .queue_priorities(priorities)
1462 })
1463 .collect::<Vec<_>>();
1464
1465 let mut extensions_to_enable = self
1466 .physical_device
1467 .extensions_to_enable
1468 .iter()
1469 .map(|ext| ext.as_ptr())
1470 .collect::<Vec<_>>();
1471
1472 if self.physical_device.surface.is_some()
1473 || self.physical_device.defer_surface_initialization
1474 {
1475 extensions_to_enable.push(vk::KHR_SWAPCHAIN_EXTENSION.name.as_ptr());
1476 }
1477
1478 let mut device_create_info = vk::DeviceCreateInfo::builder()
1479 .queue_create_infos(&queue_create_infos)
1480 .enabled_extension_names(&extensions_to_enable);
1481
1482 let requested_features_chain = &mut self.physical_device.requested_features_chain;
1483
1484 let mut features2 =
1485 vk::PhysicalDeviceFeatures2::builder().features(self.physical_device.features);
1486
1487 if self.instance.instance_version >= Version::V1_1_0
1488 || self.physical_device.properties2_ext_enabled
1489 {
1490 device_create_info = device_create_info.push_next(&mut features2);
1491
1492 for node in requested_features_chain.nodes.iter_mut() {
1493 match node {
1494 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan11(f) => {
1495 device_create_info = device_create_info.push_next(f)
1496 }
1497 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan12(f) => {
1498 device_create_info = device_create_info.push_next(f)
1499 }
1500 VulkanPhysicalDeviceFeature2::PhysicalDeviceVulkan13(f) => {
1501 device_create_info = device_create_info.push_next(f)
1502 }
1503 }
1504 }
1505 }
1506
1507 let device = unsafe {
1508 self.instance.instance.create_device(
1509 self.physical_device.physical_device,
1510 &device_create_info,
1511 self.allocation_callbacks.as_ref(),
1512 )
1513 }?;
1514
1515 let instance = self.instance;
1516 let physical_device = self.physical_device;
1517
1518 let surface = physical_device.surface;
1519 let allocation_callbacks = self.allocation_callbacks;
1520
1521 Ok(Device {
1522 instance,
1523 device,
1524 surface,
1525 physical_device,
1526 allocation_callbacks,
1527 })
1528 }
1529}
1530
1531#[derive(Debug)]
1532pub struct Device {
1533 instance: Arc<Instance>,
1534 device: vulkanalia::Device,
1535 physical_device: PhysicalDevice,
1536 surface: Option<vk::SurfaceKHR>,
1537 allocation_callbacks: Option<AllocationCallbacks>,
1538}
1539
1540#[derive(Debug, Clone, PartialOrd, PartialEq, Eq, Ord)]
1541pub enum QueueType {
1542 Present,
1543 Graphics,
1544 Compute,
1545 Transfer,
1546}
1547
1548impl Device {
1549 pub fn device(&self) -> &vulkanalia::Device {
1550 &self.device
1551 }
1552
1553 pub fn physical_device(&self) -> &PhysicalDevice {
1554 &self.physical_device
1555 }
1556
1557 pub fn get_queue(&self, queue: QueueType) -> crate::Result<(usize, vk::Queue)> {
1558 let index = match queue {
1559 QueueType::Present => get_present_queue_index(
1560 &self.instance.instance,
1561 self.physical_device.physical_device,
1562 self.surface,
1563 &self.physical_device.queue_families,
1564 )
1565 .ok_or(crate::QueueError::PresentUnavailable),
1566 QueueType::Graphics => get_first_queue_index(
1567 &self.physical_device.queue_families,
1568 vk::QueueFlags::GRAPHICS,
1569 )
1570 .ok_or(crate::QueueError::GraphicsUnavailable),
1571 QueueType::Compute => get_separate_queue_index(
1572 &self.physical_device.queue_families,
1573 vk::QueueFlags::COMPUTE,
1574 vk::QueueFlags::TRANSFER,
1575 )
1576 .ok_or(crate::QueueError::ComputeUnavailable),
1577 QueueType::Transfer => get_separate_queue_index(
1578 &self.physical_device.queue_families,
1579 vk::QueueFlags::TRANSFER,
1580 vk::QueueFlags::COMPUTE,
1581 )
1582 .ok_or(crate::QueueError::TransferUnavailable),
1583 }?;
1584
1585 Ok((index, unsafe {
1586 self.device.get_device_queue(index as _, 0)
1587 }))
1588 }
1589
1590 pub fn get_dedicated_queue(&self, queue: QueueType) -> crate::Result<vk::Queue> {
1591 let index = match queue {
1592 QueueType::Compute => get_dedicated_queue_index(
1593 &self.physical_device.queue_families,
1594 vk::QueueFlags::COMPUTE,
1595 vk::QueueFlags::TRANSFER,
1596 )
1597 .ok_or(crate::QueueError::ComputeUnavailable),
1598 QueueType::Transfer => get_dedicated_queue_index(
1599 &self.physical_device.queue_families,
1600 vk::QueueFlags::TRANSFER,
1601 vk::QueueFlags::COMPUTE,
1602 )
1603 .ok_or(crate::QueueError::TransferUnavailable),
1604 _ => return Err(crate::QueueError::InvalidQueueFamilyIndex.into()),
1605 }?;
1606
1607 let info = vk::DeviceQueueInfo2::builder()
1608 .queue_family_index(index as _)
1609 .queue_index(0);
1610
1611 Ok(unsafe { self.device.get_device_queue2(&info) })
1612 }
1613
1614 pub fn destroy(&self) {
1615 unsafe {
1616 self.device
1617 .destroy_device(self.allocation_callbacks.as_ref());
1618 }
1619 }
1620}
1621
1622impl AsRef<vulkanalia::Device> for Device {
1623 fn as_ref(&self) -> &vulkanalia::Device {
1624 &self.device
1625 }
1626}
1627
1628impl Deref for Device {
1629 type Target = vulkanalia::Device;
1630
1631 fn deref(&self) -> &Self::Target {
1632 &self.device
1633 }
1634}