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