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