1use {
4 super::{
5 DriverError,
6 instance::{ApiVersion, Instance, InstanceInfoBuilder},
7 physical_device::PhysicalDevice,
8 },
9 ash::{ext, khr, vk},
10 derive_builder::Builder,
11 gpu_allocator::{
12 AllocatorDebugSettings,
13 vulkan::{Allocator, AllocatorCreateDesc},
14 },
15 log::{error, info, trace, warn},
16 raw_window_handle::HasDisplayHandle,
17 std::{
18 collections::HashMap,
19 ffi::CString,
20 fmt::{Debug, Formatter},
21 mem::{ManuallyDrop, forget},
22 ops::Deref,
23 slice,
24 sync::Arc,
25 sync::atomic::{AtomicU64, Ordering},
26 thread::panicking,
27 time::Instant,
28 },
29};
30
31#[cfg(feature = "parking_lot")]
32use parking_lot::Mutex;
33
34#[cfg(not(feature = "parking_lot"))]
35use std::sync::Mutex;
36
37fn select_physical_device(
38 instance: &Instance,
39 mut index: usize,
40) -> Result<PhysicalDevice, DriverError> {
41 let mut physical_devices = Instance::physical_devices(instance)?
42 .into_iter()
43 .collect::<Vec<_>>();
44 if physical_devices.is_empty() {
45 warn!("unable to find physical devices");
46
47 return Err(DriverError::Unsupported);
48 }
49
50 if index >= physical_devices.len() {
51 index = 0;
52 }
53
54 let physical_device = physical_devices.remove(index);
55
56 Ok(physical_device)
57}
58
59#[read_only::embed]
61#[derive(Clone)]
62pub struct Device {
63 #[readonly]
64 pub(self) inner: Arc<DeviceInner>,
65
66 #[readonly]
75 pub physical: Box<PhysicalDevice>,
76}
77
78impl Device {
79 pub fn begin_command_buffer(
84 this: &Self,
85 cmd: vk::CommandBuffer,
86 begin_info: &vk::CommandBufferBeginInfo,
87 ) -> Result<(), DriverError> {
88 unsafe {
89 this.begin_command_buffer(cmd, begin_info).map_err(|err| {
90 warn!("unable to begin command buffer: {err}");
91
92 match err {
93 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
94 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
95 _ => DriverError::Unsupported,
96 }
97 })
98 }
99 }
100
101 pub fn begin_debug_utils_label(
105 this: &Self,
106 command_buffer: vk::CommandBuffer,
107 label_name: impl AsRef<str>,
108 ) -> Result<(), DriverError> {
109 if !this.physical.instance.info.debug {
110 return Ok(());
111 }
112
113 let Ok(label_name) = CString::new(label_name.as_ref()) else {
114 warn!("invalid label name");
115
116 return Err(DriverError::InvalidData);
117 };
118
119 let ext = Self::try_vk_ext_debug_utils(this)?;
120
121 unsafe {
122 ext.cmd_begin_debug_utils_label(
123 command_buffer,
124 &vk::DebugUtilsLabelEXT::default().label_name(label_name.as_c_str()),
125 );
126 }
127
128 Ok(())
129 }
130
131 pub(crate) fn clear_private_data_object_name<T>(
133 this: &Self,
134 object_type: vk::ObjectType,
135 object_handle: T,
136 ) -> Result<(), DriverError>
137 where
138 T: vk::Handle + Copy,
139 {
140 if this.inner.private_data_slot.is_none() {
141 return Ok(());
142 }
143
144 if object_handle.is_null() {
145 warn!("invalid object handle");
146
147 return Err(DriverError::InvalidData);
148 }
149
150 let object_key = (object_type, object_handle.as_raw());
151 let previous_metadata_id = Self::with_object_metadata_ids(this, |object_to_metadata_id| {
152 object_to_metadata_id.remove(&object_key)
153 });
154
155 if previous_metadata_id.is_none() {
156 return Ok(());
157 }
158
159 let ext = Self::try_vk_ext_private_data(this)?;
160 let private_data_slot = this
161 .inner
162 .private_data_slot
163 .expect("missing private data slot");
164
165 if let Err(err) = unsafe { ext.set_private_data(object_handle, private_data_slot, 0) } {
166 Self::with_object_metadata_ids(this, |object_metadata_ids| {
167 if let Some(metadata_id) = previous_metadata_id {
168 object_metadata_ids.insert(object_key, metadata_id);
169 }
170 });
171
172 warn!("unable to clear private data object name: {err}");
173
174 return Err(match err {
175 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
176 DriverError::OutOfMemory
177 }
178 _ => DriverError::Unsupported,
179 });
180 }
181
182 Self::with_private_data_metadata(this, |metadata| {
183 metadata
184 .names
185 .remove(&previous_metadata_id.expect("metadata id removed"));
186 });
187
188 Ok(())
189 }
190
191 pub fn cmd_pipeline_barrier2(
197 this: &Self,
198 command_buffer: vk::CommandBuffer,
199 dependency_info: &vk::DependencyInfo,
200 ) {
201 #[cfg(feature = "checked")]
202 assert!(
203 this.physical.vk_khr_synchronization2,
204 "missing synchronization2 feature"
205 );
206
207 unsafe {
208 if this.physical.instance.info.api_version >= ApiVersion::Vulkan13 {
209 this.cmd_pipeline_barrier2(command_buffer, dependency_info);
210 } else {
211 let khr_synchronization2 = Device::expect_vk_khr_synchronization2(this);
212
213 khr_synchronization2.cmd_pipeline_barrier2(command_buffer, dependency_info);
214 }
215 }
216 }
217
218 #[profiling::function]
224 pub fn create(info: impl Into<DeviceInfo>) -> Result<Self, DriverError> {
225 let DeviceInfo {
226 debug,
227 physical_device_index,
228 } = info.into();
229 let instance_info = InstanceInfoBuilder::default().debug(debug);
230 let instance = Instance::create(instance_info)?;
231 let physical_device = select_physical_device(&instance, physical_device_index)?;
232
233 Self::try_from_physical_device(physical_device)
234 }
235
236 pub fn create_fence(this: &Self, signaled: bool) -> Result<vk::Fence, DriverError> {
242 let mut flags = vk::FenceCreateFlags::empty();
243
244 if signaled {
245 flags |= vk::FenceCreateFlags::SIGNALED;
246 }
247
248 let create_info = vk::FenceCreateInfo::default().flags(flags);
249 let allocation_callbacks = None;
250
251 unsafe {
252 this.create_fence(&create_info, allocation_callbacks)
253 .map_err(|err| {
254 warn!("unable to create fence: {err}");
255
256 DriverError::OutOfMemory
257 })
258 }
259 }
260
261 pub fn create_semaphore(this: &Self) -> Result<vk::Semaphore, DriverError> {
265 let create_info = vk::SemaphoreCreateInfo::default();
266 let allocation_callbacks = None;
267
268 unsafe {
269 this.create_semaphore(&create_info, allocation_callbacks)
270 .map_err(|err| {
271 warn!("unable to create semaphore: {err}");
272
273 DriverError::OutOfMemory
274 })
275 }
276 }
277
278 pub fn end_command_buffer(this: &Self, cmd: vk::CommandBuffer) -> Result<(), DriverError> {
285 unsafe {
286 this.end_command_buffer(cmd).map_err(|err| {
287 warn!("unable to end command buffer: {err}");
288
289 match err {
290 vk::Result::ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR => DriverError::InvalidData,
291 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
292 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
293 _ => DriverError::Unsupported,
294 }
295 })
296 }
297 }
298
299 pub fn end_debug_utils_label(
303 this: &Self,
304 command_buffer: vk::CommandBuffer,
305 ) -> Result<(), DriverError> {
306 if !this.physical.instance.info.debug {
307 return Ok(());
308 }
309
310 let ext = Self::try_vk_ext_debug_utils(this)?;
311
312 unsafe {
313 ext.cmd_end_debug_utils_label(command_buffer);
314 }
315
316 Ok(())
317 }
318
319 pub(crate) fn expect_vk_khr_acceleration_structure(
326 this: &Self,
327 ) -> &khr::acceleration_structure::Device {
328 this.inner
329 .vk_khr_acceleration_structure
330 .as_ref()
331 .expect("missing VK_KHR_acceleration_structure")
332 }
333
334 pub(crate) fn expect_vk_khr_present_wait(this: &Self) -> &khr::present_wait::Device {
340 this.inner
341 .vk_khr_present_wait
342 .as_ref()
343 .expect("missing VK_KHR_present_wait")
344 }
345
346 pub(crate) fn expect_vk_khr_ray_tracing_pipeline(
353 this: &Self,
354 ) -> &khr::ray_tracing_pipeline::Device {
355 this.inner
356 .vk_khr_ray_tracing_pipeline
357 .as_ref()
358 .expect("missing VK_KHR_ray_tracing_pipeline")
359 }
360
361 pub(crate) fn expect_vk_khr_surface(this: &Self) -> &khr::surface::Instance {
367 this.inner
368 .vk_khr_surface
369 .as_ref()
370 .expect("missing VK_KHR_surface")
371 }
372
373 pub(crate) fn expect_vk_khr_synchronization2(this: &Self) -> &khr::synchronization2::Device {
380 this.inner
381 .vk_khr_synchronization2
382 .as_ref()
383 .expect("missing VK_KHR_synchronization2")
384 }
385
386 pub(crate) fn expect_vk_khr_swapchain(this: &Self) -> &khr::swapchain::Device {
392 this.inner
393 .vk_khr_swapchain
394 .as_ref()
395 .expect("missing VK_KHR_swapchain")
396 }
397
398 pub(crate) fn forget_private_data_object_name<T>(
400 this: &Self,
401 object_type: vk::ObjectType,
402 object_handle: T,
403 ) where
404 T: vk::Handle + Copy,
405 {
406 if this.inner.private_data_slot.is_none() || object_handle.is_null() {
407 return;
408 }
409
410 let object_key = (object_type, object_handle.as_raw());
411 let Some(metadata_id) = Self::with_object_metadata_ids(this, |object_metadata_ids| {
412 object_metadata_ids.remove(&object_key)
413 }) else {
414 return;
415 };
416
417 Self::with_private_data_metadata(this, |metadata| {
418 metadata.names.remove(&metadata_id);
419 });
420 }
421
422 pub(crate) fn is_same(lhs: &Self, rhs: &Self) -> bool {
424 Arc::ptr_eq(&lhs.inner, &rhs.inner)
425 }
426
427 pub(crate) fn pipeline_cache(this: &Self) -> vk::PipelineCache {
429 this.inner.pipeline_cache
430 }
431
432 pub(crate) fn private_data_object_name<T>(
437 this: &Self,
438 object_type: vk::ObjectType,
439 object_handle: T,
440 ) -> Option<String>
441 where
442 T: vk::Handle + Copy,
443 {
444 this.inner.private_data_slot?;
445
446 if object_handle.is_null() {
447 return None;
448 }
449
450 let object_key = (object_type, object_handle.as_raw());
451 Self::with_private_data_metadata(this, |metadata| {
452 let metadata_id = metadata.object_metadata_ids.get(&object_key)?;
453
454 metadata.names.get(metadata_id).cloned()
455 })
456 }
457
458 pub fn queue_submit(
462 this: &Self,
463 queue: vk::Queue,
464 submits: &[vk::SubmitInfo],
465 fence: vk::Fence,
466 ) -> Result<(), DriverError> {
467 unsafe {
468 this.queue_submit(queue, submits, fence).map_err(|err| {
469 warn!("unable to queue submits: {err}");
470
471 match err {
472 vk::Result::ERROR_DEVICE_LOST => DriverError::InvalidData,
473 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
474 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
475 _ => DriverError::Unsupported,
476 }
477 })
478 }
479 }
480
481 pub fn queue_submit2(
487 this: &Self,
488 queue: vk::Queue,
489 submits: &[vk::SubmitInfo2],
490 fence: vk::Fence,
491 ) -> Result<(), DriverError> {
492 #[cfg(feature = "checked")]
493 assert!(this.physical.vk_khr_synchronization2);
494
495 unsafe {
496 if this.physical.instance.info.api_version >= ApiVersion::Vulkan13 {
497 this.queue_submit2(queue, submits, fence)
499 } else {
500 let khr_synchronization2 = Device::expect_vk_khr_synchronization2(this);
501
502 khr_synchronization2.queue_submit2(queue, submits, fence)
504 }
505 .map_err(|err| {
506 warn!("unable to queue submit2 submissions: {err}");
507
508 match err {
509 vk::Result::ERROR_DEVICE_LOST => DriverError::InvalidData,
510 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
511 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
512 _ => DriverError::Unsupported,
513 }
514 })
515 }
516 }
517
518 pub fn queue_wait_idle(this: &Self, queue: vk::Queue) -> Result<(), DriverError> {
520 unsafe {
521 this.queue_wait_idle(queue).map_err(|err| {
522 warn!("unable to wait for queue idle: {err}");
523
524 match err {
525 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
526 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
527 vk::Result::ERROR_DEVICE_LOST | vk::Result::ERROR_VALIDATION_FAILED_EXT => {
528 DriverError::InvalidData
529 }
530 _ => DriverError::Unsupported,
531 }
532 })
533 }
534 }
535
536 pub fn reset_fences(this: &Self, fences: &[vk::Fence]) -> Result<(), DriverError> {
540 unsafe {
541 this.reset_fences(fences).map_err(|err| {
542 warn!("unable to reset fences: {err}");
543
544 match err {
545 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => DriverError::OutOfMemory,
546 _ => DriverError::Unsupported,
547 }
548 })
549 }
550 }
551
552 pub fn set_debug_utils_object_name<T>(
556 this: &Self,
557 object_handle: T,
558 object_name: impl AsRef<str>,
559 ) -> Result<(), DriverError>
560 where
561 T: vk::Handle + Copy,
562 {
563 if !this.physical.instance.info.debug {
564 return Ok(());
565 }
566
567 if object_handle.is_null() {
568 warn!("invalid object handle");
569
570 return Err(DriverError::InvalidData);
571 }
572
573 let Ok(object_name) = CString::new(object_name.as_ref()) else {
574 warn!("invalid object name");
575
576 return Err(DriverError::InvalidData);
577 };
578
579 let ext = Self::try_vk_ext_debug_utils(this)?;
580
581 unsafe {
582 match ext.set_debug_utils_object_name(
583 &vk::DebugUtilsObjectNameInfoEXT::default()
584 .object_handle(object_handle)
585 .object_name(object_name.as_c_str()),
586 ) {
587 Err(
588 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY,
589 ) => Err(DriverError::OutOfMemory),
590 Err(vk::Result::ERROR_VALIDATION_FAILED_EXT) => Err(DriverError::InvalidData),
591 Err(err) => {
592 warn!("unable to set debug utils object name: {err}");
593
594 Err(DriverError::Unsupported)
595 }
596 Ok(_) => Ok(()),
597 }
598 }
599 }
600
601 pub(crate) fn set_private_data_object_name<T>(
605 this: &Self,
606 object_type: vk::ObjectType,
607 object_handle: T,
608 object_name: impl AsRef<str>,
609 ) -> Result<(), DriverError>
610 where
611 T: vk::Handle + Copy,
612 {
613 if this.inner.private_data_slot.is_none() {
614 return Ok(());
615 }
616
617 if object_handle.is_null() {
618 warn!("invalid object handle");
619
620 return Err(DriverError::InvalidData);
621 }
622
623 let object_key = (object_type, object_handle.as_raw());
624 let metadata_id = this
625 .inner
626 .private_data_name_id
627 .fetch_add(1, Ordering::Relaxed)
628 + 1;
629
630 let (previous_metadata_id, previous_name) =
631 Self::with_private_data_metadata(this, |metadata| {
632 let previous_metadata_id =
633 metadata.object_metadata_ids.insert(object_key, metadata_id);
634 let previous_name = previous_metadata_id.and_then(|id| metadata.names.remove(&id));
635
636 metadata
637 .names
638 .insert(metadata_id, object_name.as_ref().to_owned());
639
640 (previous_metadata_id, previous_name)
641 });
642
643 let ext = Self::try_vk_ext_private_data(this)?;
644 let private_data_slot = this
645 .inner
646 .private_data_slot
647 .expect("missing private data slot");
648
649 if let Err(err) =
650 unsafe { ext.set_private_data(object_handle, private_data_slot, metadata_id) }
651 {
652 Self::with_private_data_metadata(this, |metadata| {
653 let _ = metadata.names.remove(&metadata_id);
654 match previous_metadata_id {
655 Some(id) => {
656 metadata.object_metadata_ids.insert(object_key, id);
657 if let Some(name) = previous_name {
658 metadata.names.insert(id, name);
659 }
660 }
661 None => {
662 metadata.object_metadata_ids.remove(&object_key);
663 }
664 }
665 });
666
667 warn!("unable to set private data object name: {err}");
668
669 return Err(match err {
670 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
671 DriverError::OutOfMemory
672 }
673 _ => DriverError::Unsupported,
674 });
675 }
676
677 Ok(())
678 }
679
680 #[profiling::function]
688 pub unsafe fn try_from_ash(
689 device: ash::Device,
690 physical_device: PhysicalDevice,
691 ) -> Result<Self, DriverError> {
692 let debug = physical_device.instance.info.debug;
693
694 if debug && !Instance::supports_debug_utils(&physical_device.instance) {
695 error!("unsupported VK_EXT_debug_utils");
696
697 return Err(DriverError::Unsupported);
698 }
699
700 if debug && !physical_device.vk_ext_private_data {
701 error!("unsupported VK_EXT_private_data");
702
703 return Err(DriverError::Unsupported);
704 }
705
706 let mut debug_settings = AllocatorDebugSettings::default();
707 debug_settings.log_leaks_on_shutdown = debug;
708 debug_settings.log_memory_information = debug;
709 debug_settings.log_allocations = debug;
710
711 let allocator = Allocator::new(&AllocatorCreateDesc {
712 instance: (*physical_device.instance).clone(),
713 device: device.clone(),
714 physical_device: physical_device.handle,
715 debug_settings,
716 buffer_device_address: true,
717 allocation_sizes: Default::default(),
718 })
719 .map_err(|err| {
720 warn!("unable to create allocator: {err}");
721
722 DriverError::Unsupported
723 })?;
724
725 let mut queues = Vec::with_capacity(physical_device.queue_families.len());
726
727 for (queue_family_index, properties) in physical_device.queue_families.iter().enumerate() {
728 let mut queue_family = Vec::with_capacity(properties.queue_count as _);
729
730 for queue_index in 0..properties.queue_count {
731 queue_family.push(Mutex::new(unsafe {
732 device.get_device_queue(queue_family_index as _, queue_index)
733 }));
734 }
735
736 queues.push(queue_family.into_boxed_slice());
737 }
738
739 let vk_ext_debug_utils = Some(ext::debug_utils::Device::new(
740 &physical_device.instance,
741 &device,
742 ));
743 let vk_ext_private_data = physical_device
744 .vk_ext_private_data
745 .then(|| ext::private_data::Device::new(&physical_device.instance, &device));
746 let vk_ext_private_data_slot = vk_ext_private_data
747 .as_ref()
748 .map(|vk_ext_private_data| unsafe {
749 vk_ext_private_data
750 .create_private_data_slot(
751 &vk::PrivateDataSlotCreateInfoEXT::default()
752 .flags(vk::PrivateDataSlotCreateFlagsEXT::empty()),
753 None,
754 )
755 .map_err(|err| {
756 warn!("unable to create private data slot: {err}");
757
758 DriverError::Unsupported
759 })
760 })
761 .transpose()?;
762 let vk_khr_present_wait = physical_device
763 .vk_khr_present_wait
764 .is_some()
765 .then(|| khr::present_wait::Device::new(&physical_device.instance, &device));
766 let vk_khr_surface = physical_device.vk_khr_swapchain.then(|| {
767 let entry = Instance::entry(&physical_device.instance);
768 khr::surface::Instance::new(entry, &physical_device.instance)
769 });
770 let vk_khr_swapchain = physical_device
771 .vk_khr_swapchain
772 .then(|| khr::swapchain::Device::new(&physical_device.instance, &device));
773 let vk_khr_acceleration_structure = physical_device
774 .vk_khr_acceleration_structure
775 .is_some()
776 .then(|| khr::acceleration_structure::Device::new(&physical_device.instance, &device));
777 let vk_khr_ray_tracing_pipeline = physical_device
778 .vk_khr_ray_tracing_pipeline
779 .as_ref()
780 .is_some_and(|ext| ext.features.ray_tracing_pipeline)
781 .then(|| khr::ray_tracing_pipeline::Device::new(&physical_device.instance, &device));
782 let vk_khr_synchronization2 = physical_device
783 .vk_khr_synchronization2
784 .then(|| khr::synchronization2::Device::new(&physical_device.instance, &device));
785
786 let pipeline_cache =
787 unsafe { device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None) }
788 .map_err(|err| {
789 warn!("unable to create pipeline cache: {err}");
790
791 DriverError::Unsupported
792 })?;
793
794 Ok(Self {
795 read_only: ReadOnlyDevice {
796 inner: Arc::new(DeviceInner {
797 allocator: ManuallyDrop::new(Mutex::new(allocator)),
798 device,
799 pipeline_cache,
800 queues: queues.into_boxed_slice(),
801 vk_ext_debug_utils,
802 vk_ext_private_data,
803 vk_khr_acceleration_structure,
804 vk_khr_present_wait,
805 vk_khr_ray_tracing_pipeline,
806 vk_khr_surface,
807 vk_khr_swapchain,
808 vk_khr_synchronization2,
809 private_data_slot: vk_ext_private_data_slot,
810 private_data_name_id: AtomicU64::new(0),
811 private_data_metadata: Mutex::new(Default::default()),
812 }),
813 physical: Box::new(physical_device),
814 },
815 })
816 }
817
818 #[profiling::function]
820 pub fn try_from_display(
821 display: impl HasDisplayHandle,
822 info: impl Into<DeviceInfo>,
823 ) -> Result<Self, DriverError> {
824 let DeviceInfo {
825 debug,
826 physical_device_index,
827 } = info.into();
828 let instance_info = InstanceInfoBuilder::default().debug(debug);
829 let instance = Instance::try_from_display(display, instance_info)?;
830 let physical_device = select_physical_device(&instance, physical_device_index)?;
831
832 Self::try_from_physical_device(physical_device)
833 }
834
835 #[profiling::function]
837 pub fn try_from_physical_device(physical_device: PhysicalDevice) -> Result<Self, DriverError> {
838 let device = unsafe {
839 physical_device.create_ash_device(|device_create_info| {
840 physical_device.instance.create_device(
841 physical_device.handle,
842 &device_create_info,
843 None,
844 )
845 })
846 }
847 .map_err(|err| {
848 error!("unable to create device: {err}");
849
850 DriverError::Unsupported
851 })?;
852
853 info!("created {}", physical_device.properties_v1_0.device_name);
854
855 unsafe { Self::try_from_ash(device, physical_device) }
856 }
857
858 pub(crate) fn try_clear_private_data_object_name<T>(
859 this: &Self,
860 object_type: vk::ObjectType,
861 object_handle: T,
862 ) where
863 T: vk::Handle + Copy,
864 {
865 let _ = Self::clear_private_data_object_name(this, object_type, object_handle);
866 }
867
868 pub fn try_set_debug_utils_object_name<T>(
872 this: &Self,
873 object_handle: T,
874 object_name: impl AsRef<str>,
875 ) where
876 T: vk::Handle + Copy,
877 {
878 let _ = Self::set_debug_utils_object_name(this, object_handle, object_name);
879 }
880
881 pub(crate) fn try_set_private_data_object_name<T>(
885 this: &Self,
886 object_type: vk::ObjectType,
887 object_handle: T,
888 object_name: impl AsRef<str>,
889 ) where
890 T: vk::Handle + Copy,
891 {
892 let _ = Self::set_private_data_object_name(this, object_type, object_handle, object_name);
893 }
894
895 fn try_vk_ext_debug_utils(this: &Self) -> Result<&ext::debug_utils::Device, DriverError> {
896 this.inner
897 .vk_ext_debug_utils
898 .as_ref()
899 .ok_or(DriverError::Unsupported)
900 }
901
902 fn try_vk_ext_private_data(this: &Self) -> Result<&ext::private_data::Device, DriverError> {
903 this.inner
904 .vk_ext_private_data
905 .as_ref()
906 .ok_or(DriverError::Unsupported)
907 }
908
909 #[profiling::function]
911 pub(crate) fn wait_for_fence(this: &Self, fence: &vk::Fence) -> Result<(), DriverError> {
912 Device::wait_for_fences(this, slice::from_ref(fence))
913 }
914
915 #[profiling::function]
920 pub(crate) fn wait_for_fences(this: &Self, fences: &[vk::Fence]) -> Result<(), DriverError> {
921 unsafe {
922 match this.wait_for_fences(fences, true, 100) {
923 Ok(_) => return Ok(()),
924 Err(err) if err == vk::Result::ERROR_DEVICE_LOST => {
925 error!("invalid device state: lost");
926
927 return Err(DriverError::InvalidData);
928 }
929 Err(err) if err == vk::Result::TIMEOUT => {
930 trace!("waiting...");
931 }
932 Err(err) => {
933 warn!("unable to wait for fences during polling phase: {err}");
934
935 return Err(DriverError::OutOfMemory);
936 }
937 }
938
939 let started = cfg!(debug_assertions).then(Instant::now);
940
941 match this.wait_for_fences(fences, true, u64::MAX) {
942 Ok(_) => (),
943 Err(err) if err == vk::Result::ERROR_DEVICE_LOST => {
944 error!("invalid device state: lost");
945
946 return Err(DriverError::InvalidData);
947 }
948 Err(err) => {
949 warn!("unable to wait for fences to completion: {err}");
950
951 return Err(DriverError::OutOfMemory);
952 }
953 }
954
955 if let Some(started) = started {
956 let elapsed = Instant::now() - started;
957 let elapsed_millis = elapsed.as_millis();
958
959 if elapsed_millis > 0 {
960 warn!("slow fence wait: {} ms", elapsed_millis);
961 }
962 }
963 }
964
965 Ok(())
966 }
967
968 pub fn wait_idle(this: &Self) -> Result<(), DriverError> {
970 unsafe {
971 this.device_wait_idle().map_err(|err| {
972 warn!("unable to wait for device idle: {err}");
973
974 match err {
975 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
976 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
977 vk::Result::ERROR_DEVICE_LOST | vk::Result::ERROR_VALIDATION_FAILED_EXT => {
978 DriverError::InvalidData
979 }
980 _ => DriverError::Unsupported,
981 }
982 })
983 }
984 }
985
986 pub(crate) fn with_allocator<R>(this: &Self, f: impl FnOnce(&mut Allocator) -> R) -> R {
988 let allocator = this.inner.allocator.lock();
989
990 #[cfg(not(feature = "parking_lot"))]
991 let allocator = allocator.expect("poisoned allocator lock");
992
993 let mut allocator = allocator;
994
995 f(&mut allocator)
996 }
997
998 fn with_object_metadata_ids<R>(
999 this: &Self,
1000 f: impl FnOnce(&mut HashMap<(vk::ObjectType, u64), u64>) -> R,
1001 ) -> R {
1002 Self::with_private_data_metadata(this, |metadata| f(&mut metadata.object_metadata_ids))
1003 }
1004
1005 fn with_private_data_metadata<R>(
1006 this: &Self,
1007 f: impl FnOnce(&mut PrivateDataMetadata) -> R,
1008 ) -> R {
1009 let mut metadata = this.inner.private_data_metadata.lock();
1010
1011 #[cfg(not(feature = "parking_lot"))]
1012 let mut metadata = metadata.expect("poisoned private data metadata");
1013
1014 f(&mut metadata)
1015 }
1016
1017 pub fn with_queue<R>(
1026 this: &Self,
1027 queue_family_index: u32,
1028 queue_index: u32,
1029 f: impl FnOnce(vk::Queue) -> R,
1030 ) -> R {
1031 let queue_family = this
1032 .inner
1033 .queues
1034 .get(queue_family_index as usize)
1035 .expect("invalid queue family index");
1036 let queue = queue_family
1037 .get(queue_index as usize)
1038 .expect("invalid queue index");
1039 #[cfg(not(feature = "parking_lot"))]
1040 let guard = queue.lock().expect("poisoned queue lock");
1041
1042 #[cfg(feature = "parking_lot")]
1043 let guard = queue.lock();
1044
1045 f(*guard)
1046 }
1047}
1048
1049impl Debug for Device {
1050 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1051 f.debug_struct(stringify!(Device))
1052 .field("handle", &self.inner.device.handle())
1053 .field("physical", &self.physical)
1054 .finish_non_exhaustive()
1055 }
1056}
1057
1058#[cfg(doc)]
1059impl Deref for Device {
1060 type Target = ash::Device;
1061
1062 fn deref(&self) -> &Self::Target {
1063 unreachable!()
1064 }
1065}
1066
1067impl Eq for Device {}
1068
1069impl PartialEq for Device {
1070 fn eq(&self, other: &Self) -> bool {
1071 Arc::ptr_eq(&self.inner, &other.inner)
1072 }
1073}
1074
1075#[derive(Builder, Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
1077#[builder(
1078 build_fn(private, name = "fallible_build"),
1079 derive(Clone, Copy, Debug),
1080 pattern = "owned"
1081)]
1082pub struct DeviceInfo {
1083 #[builder(default)]
1102 pub debug: bool,
1103
1104 #[builder(default)]
1107 pub physical_device_index: usize,
1108}
1109
1110impl DeviceInfo {
1111 pub fn builder() -> DeviceInfoBuilder {
1113 Default::default()
1114 }
1115
1116 pub fn into_builder(self) -> DeviceInfoBuilder {
1118 DeviceInfoBuilder {
1119 debug: Some(self.debug),
1120 physical_device_index: Some(self.physical_device_index),
1121 }
1122 }
1123}
1124
1125impl From<DeviceInfoBuilder> for DeviceInfo {
1126 fn from(info: DeviceInfoBuilder) -> Self {
1127 info.build()
1128 }
1129}
1130
1131impl DeviceInfoBuilder {
1132 #[inline(always)]
1134 pub fn build(self) -> DeviceInfo {
1135 self.fallible_build().expect("invalid device info")
1136 }
1137}
1138
1139struct DeviceInner {
1140 allocator: ManuallyDrop<Mutex<Allocator>>,
1141 device: ash::Device,
1142 pipeline_cache: vk::PipelineCache,
1143 queues: Box<[Box<[Mutex<vk::Queue>]>]>,
1144 vk_ext_debug_utils: Option<ext::debug_utils::Device>,
1145 vk_ext_private_data: Option<ext::private_data::Device>,
1146 vk_khr_acceleration_structure: Option<khr::acceleration_structure::Device>,
1147 vk_khr_present_wait: Option<khr::present_wait::Device>,
1148 vk_khr_ray_tracing_pipeline: Option<khr::ray_tracing_pipeline::Device>,
1149 vk_khr_surface: Option<khr::surface::Instance>,
1150 vk_khr_swapchain: Option<khr::swapchain::Device>,
1151 vk_khr_synchronization2: Option<khr::synchronization2::Device>,
1152 private_data_slot: Option<vk::PrivateDataSlot>,
1153 private_data_name_id: AtomicU64,
1154 private_data_metadata: Mutex<PrivateDataMetadata>,
1155}
1156
1157#[derive(Default)]
1158struct PrivateDataMetadata {
1159 object_metadata_ids: HashMap<(vk::ObjectType, u64), u64>,
1160 names: HashMap<u64, String>,
1161}
1162
1163impl Drop for DeviceInner {
1164 #[profiling::function]
1165 fn drop(&mut self) {
1166 if panicking() {
1167 unsafe {
1169 forget(ManuallyDrop::take(&mut self.allocator));
1170 }
1171
1172 return;
1173 }
1174
1175 if let Err(err) = unsafe { self.device.device_wait_idle() } {
1178 warn!("device_wait_idle() failed: {err}");
1179 }
1180
1181 unsafe {
1182 self.device
1183 .destroy_pipeline_cache(self.pipeline_cache, None);
1184
1185 if let (Some(vk_ext_private_data), Some(private_data_slot)) = (
1186 self.vk_ext_private_data.as_ref(),
1187 self.private_data_slot.take(),
1188 ) {
1189 vk_ext_private_data.destroy_private_data_slot(private_data_slot, None);
1190 }
1191
1192 ManuallyDrop::drop(&mut self.allocator);
1193 }
1194
1195 unsafe {
1196 self.device.destroy_device(None);
1197 }
1198 }
1199}
1200
1201#[doc(hidden)]
1202impl Clone for ReadOnlyDevice {
1203 fn clone(&self) -> Self {
1204 Self {
1205 inner: self.inner.clone(),
1206 physical: self.physical.clone(),
1207 }
1208 }
1209}
1210
1211#[doc(hidden)]
1212impl Deref for ReadOnlyDevice {
1213 type Target = ash::Device;
1214
1215 fn deref(&self) -> &Self::Target {
1216 &self.inner.device
1217 }
1218}
1219
1220#[cfg(test)]
1221mod test {
1222 use super::*;
1223
1224 type Info = DeviceInfo;
1225 type Builder = DeviceInfoBuilder;
1226
1227 #[test]
1228 pub fn device_info() {
1229 Info::default().into_builder().build();
1230 }
1231
1232 #[test]
1233 pub fn device_info_builder() {
1234 Builder::default().build();
1235 }
1236}