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 identity(this: &Self) -> usize {
428 Arc::as_ptr(&this.inner) as usize
429 }
430
431 pub(crate) fn pipeline_cache(this: &Self) -> vk::PipelineCache {
433 this.inner.pipeline_cache
434 }
435
436 pub fn merge_pipeline_cache_data(this: &Self, data: &[u8]) -> Result<(), DriverError> {
438 let info = vk::PipelineCacheCreateInfo::default().initial_data(data);
439
440 let source =
441 unsafe { this.create_pipeline_cache(&info, None) }.map_err(|err| match err {
442 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
443 DriverError::OutOfMemory
444 }
445 _ => DriverError::Unsupported,
446 })?;
447
448 let result = unsafe { this.merge_pipeline_caches(this.inner.pipeline_cache, &[source]) }
451 .map_err(|err| match err {
452 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
453 DriverError::OutOfMemory
454 }
455 _ => DriverError::Unsupported,
456 });
457
458 unsafe { this.destroy_pipeline_cache(source, None) };
460
461 result
463 }
464
465 pub fn pipeline_cache_data(this: &Self) -> Result<Box<[u8]>, DriverError> {
467 unsafe { this.get_pipeline_cache_data(this.inner.pipeline_cache) }
468 .map_err(|err| match err {
469 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
470 DriverError::OutOfMemory
471 }
472 _ => DriverError::Unsupported,
473 })
474 .map(Vec::into_boxed_slice)
475 }
476
477 pub(crate) fn private_data_object_name<T>(
482 this: &Self,
483 object_type: vk::ObjectType,
484 object_handle: T,
485 ) -> Option<String>
486 where
487 T: vk::Handle + Copy,
488 {
489 this.inner.private_data_slot?;
490
491 if object_handle.is_null() {
492 return None;
493 }
494
495 let object_key = (object_type, object_handle.as_raw());
496 Self::with_private_data_metadata(this, |metadata| {
497 let metadata_id = metadata.object_metadata_ids.get(&object_key)?;
498
499 metadata.names.get(metadata_id).cloned()
500 })
501 }
502
503 pub fn queue_submit(
507 this: &Self,
508 queue: vk::Queue,
509 submits: &[vk::SubmitInfo],
510 fence: vk::Fence,
511 ) -> Result<(), DriverError> {
512 unsafe {
513 this.queue_submit(queue, submits, fence).map_err(|err| {
514 warn!("unable to queue submits: {err}");
515
516 match err {
517 vk::Result::ERROR_DEVICE_LOST => DriverError::InvalidData,
518 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
519 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
520 _ => DriverError::Unsupported,
521 }
522 })
523 }
524 }
525
526 pub fn queue_submit2(
532 this: &Self,
533 queue: vk::Queue,
534 submits: &[vk::SubmitInfo2],
535 fence: vk::Fence,
536 ) -> Result<(), DriverError> {
537 #[cfg(feature = "checked")]
538 assert!(this.physical.vk_khr_synchronization2);
539
540 unsafe {
541 if this.physical.instance.info.api_version >= ApiVersion::Vulkan13 {
542 this.queue_submit2(queue, submits, fence)
544 } else {
545 let khr_synchronization2 = Device::expect_vk_khr_synchronization2(this);
546
547 khr_synchronization2.queue_submit2(queue, submits, fence)
549 }
550 .map_err(|err| {
551 warn!("unable to queue submit2 submissions: {err}");
552
553 match err {
554 vk::Result::ERROR_DEVICE_LOST => DriverError::InvalidData,
555 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
556 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
557 _ => DriverError::Unsupported,
558 }
559 })
560 }
561 }
562
563 pub fn queue_wait_idle(this: &Self, queue: vk::Queue) -> Result<(), DriverError> {
565 unsafe {
566 this.queue_wait_idle(queue).map_err(|err| {
567 warn!("unable to wait for queue idle: {err}");
568
569 match err {
570 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
571 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
572 vk::Result::ERROR_DEVICE_LOST | vk::Result::ERROR_VALIDATION_FAILED_EXT => {
573 DriverError::InvalidData
574 }
575 _ => DriverError::Unsupported,
576 }
577 })
578 }
579 }
580
581 pub fn reset_fences(this: &Self, fences: &[vk::Fence]) -> Result<(), DriverError> {
585 unsafe {
586 this.reset_fences(fences).map_err(|err| {
587 warn!("unable to reset fences: {err}");
588
589 match err {
590 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => DriverError::OutOfMemory,
591 _ => DriverError::Unsupported,
592 }
593 })
594 }
595 }
596
597 pub fn set_debug_utils_object_name<T>(
601 this: &Self,
602 object_handle: T,
603 object_name: impl AsRef<str>,
604 ) -> Result<(), DriverError>
605 where
606 T: vk::Handle + Copy,
607 {
608 if !this.physical.instance.info.debug {
609 return Ok(());
610 }
611
612 if object_handle.is_null() {
613 warn!("invalid object handle");
614
615 return Err(DriverError::InvalidData);
616 }
617
618 let Ok(object_name) = CString::new(object_name.as_ref()) else {
619 warn!("invalid object name");
620
621 return Err(DriverError::InvalidData);
622 };
623
624 let ext = Self::try_vk_ext_debug_utils(this)?;
625
626 unsafe {
627 match ext.set_debug_utils_object_name(
628 &vk::DebugUtilsObjectNameInfoEXT::default()
629 .object_handle(object_handle)
630 .object_name(object_name.as_c_str()),
631 ) {
632 Err(
633 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY,
634 ) => Err(DriverError::OutOfMemory),
635 Err(vk::Result::ERROR_VALIDATION_FAILED_EXT) => Err(DriverError::InvalidData),
636 Err(err) => {
637 warn!("unable to set debug utils object name: {err}");
638
639 Err(DriverError::Unsupported)
640 }
641 Ok(_) => Ok(()),
642 }
643 }
644 }
645
646 pub(crate) fn set_private_data_object_name<T>(
650 this: &Self,
651 object_type: vk::ObjectType,
652 object_handle: T,
653 object_name: impl AsRef<str>,
654 ) -> Result<(), DriverError>
655 where
656 T: vk::Handle + Copy,
657 {
658 if this.inner.private_data_slot.is_none() {
659 return Ok(());
660 }
661
662 if object_handle.is_null() {
663 warn!("invalid object handle");
664
665 return Err(DriverError::InvalidData);
666 }
667
668 let object_key = (object_type, object_handle.as_raw());
669 let metadata_id = this
670 .inner
671 .private_data_name_id
672 .fetch_add(1, Ordering::Relaxed)
673 + 1;
674
675 let (previous_metadata_id, previous_name) =
676 Self::with_private_data_metadata(this, |metadata| {
677 let previous_metadata_id =
678 metadata.object_metadata_ids.insert(object_key, metadata_id);
679 let previous_name = previous_metadata_id.and_then(|id| metadata.names.remove(&id));
680
681 metadata
682 .names
683 .insert(metadata_id, object_name.as_ref().to_owned());
684
685 (previous_metadata_id, previous_name)
686 });
687
688 let ext = Self::try_vk_ext_private_data(this)?;
689 let private_data_slot = this
690 .inner
691 .private_data_slot
692 .expect("missing private data slot");
693
694 if let Err(err) =
695 unsafe { ext.set_private_data(object_handle, private_data_slot, metadata_id) }
696 {
697 Self::with_private_data_metadata(this, |metadata| {
698 let _ = metadata.names.remove(&metadata_id);
699 match previous_metadata_id {
700 Some(id) => {
701 metadata.object_metadata_ids.insert(object_key, id);
702 if let Some(name) = previous_name {
703 metadata.names.insert(id, name);
704 }
705 }
706 None => {
707 metadata.object_metadata_ids.remove(&object_key);
708 }
709 }
710 });
711
712 warn!("unable to set private data object name: {err}");
713
714 return Err(match err {
715 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY | vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
716 DriverError::OutOfMemory
717 }
718 _ => DriverError::Unsupported,
719 });
720 }
721
722 Ok(())
723 }
724
725 #[profiling::function]
733 pub unsafe fn try_from_ash(
734 device: ash::Device,
735 physical_device: PhysicalDevice,
736 ) -> Result<Self, DriverError> {
737 let debug = physical_device.instance.info.debug;
738
739 if debug && !Instance::supports_debug_utils(&physical_device.instance) {
740 error!("unsupported VK_EXT_debug_utils");
741
742 return Err(DriverError::Unsupported);
743 }
744
745 if debug && !physical_device.vk_ext_private_data {
746 error!("unsupported VK_EXT_private_data");
747
748 return Err(DriverError::Unsupported);
749 }
750
751 let mut debug_settings = AllocatorDebugSettings::default();
752 debug_settings.log_leaks_on_shutdown = debug;
753 debug_settings.log_memory_information = debug;
754 debug_settings.log_allocations = debug;
755
756 let allocator = Allocator::new(&AllocatorCreateDesc {
757 instance: (*physical_device.instance).clone(),
758 device: device.clone(),
759 physical_device: physical_device.handle,
760 debug_settings,
761 buffer_device_address: true,
762 allocation_sizes: Default::default(),
763 })
764 .map_err(|err| {
765 warn!("unable to create allocator: {err}");
766
767 DriverError::Unsupported
768 })?;
769
770 let mut queues = Vec::with_capacity(physical_device.queue_families.len());
771
772 for (queue_family_index, properties) in physical_device.queue_families.iter().enumerate() {
773 let mut queue_family = Vec::with_capacity(properties.queue_count as _);
774
775 for queue_index in 0..properties.queue_count {
776 queue_family.push(Mutex::new(unsafe {
777 device.get_device_queue(queue_family_index as _, queue_index)
778 }));
779 }
780
781 queues.push(queue_family.into_boxed_slice());
782 }
783
784 let vk_ext_debug_utils = Some(ext::debug_utils::Device::new(
785 &physical_device.instance,
786 &device,
787 ));
788 let vk_ext_private_data = physical_device
789 .vk_ext_private_data
790 .then(|| ext::private_data::Device::new(&physical_device.instance, &device));
791 let vk_ext_private_data_slot = vk_ext_private_data
792 .as_ref()
793 .map(|vk_ext_private_data| unsafe {
794 vk_ext_private_data
795 .create_private_data_slot(
796 &vk::PrivateDataSlotCreateInfoEXT::default()
797 .flags(vk::PrivateDataSlotCreateFlagsEXT::empty()),
798 None,
799 )
800 .map_err(|err| {
801 warn!("unable to create private data slot: {err}");
802
803 DriverError::Unsupported
804 })
805 })
806 .transpose()?;
807 let vk_khr_present_wait = physical_device
808 .vk_khr_present_wait
809 .is_some()
810 .then(|| khr::present_wait::Device::new(&physical_device.instance, &device));
811 let vk_khr_surface = physical_device.vk_khr_swapchain.then(|| {
812 let entry = Instance::entry(&physical_device.instance);
813 khr::surface::Instance::new(entry, &physical_device.instance)
814 });
815 let vk_khr_swapchain = physical_device
816 .vk_khr_swapchain
817 .then(|| khr::swapchain::Device::new(&physical_device.instance, &device));
818 let vk_khr_acceleration_structure = physical_device
819 .vk_khr_acceleration_structure
820 .is_some()
821 .then(|| khr::acceleration_structure::Device::new(&physical_device.instance, &device));
822 let vk_khr_ray_tracing_pipeline = physical_device
823 .vk_khr_ray_tracing_pipeline
824 .as_ref()
825 .is_some_and(|ext| ext.features.ray_tracing_pipeline)
826 .then(|| khr::ray_tracing_pipeline::Device::new(&physical_device.instance, &device));
827 let vk_khr_synchronization2 = physical_device
828 .vk_khr_synchronization2
829 .then(|| khr::synchronization2::Device::new(&physical_device.instance, &device));
830
831 let pipeline_cache =
832 unsafe { device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None) }
833 .map_err(|err| {
834 warn!("unable to create pipeline cache: {err}");
835
836 DriverError::Unsupported
837 })?;
838
839 Ok(Self {
840 read_only: ReadOnlyDevice {
841 inner: Arc::new(DeviceInner {
842 allocator: ManuallyDrop::new(Mutex::new(allocator)),
843 device,
844 pipeline_cache,
845 queues: queues.into_boxed_slice(),
846 vk_ext_debug_utils,
847 vk_ext_private_data,
848 vk_khr_acceleration_structure,
849 vk_khr_present_wait,
850 vk_khr_ray_tracing_pipeline,
851 vk_khr_surface,
852 vk_khr_swapchain,
853 vk_khr_synchronization2,
854 private_data_slot: vk_ext_private_data_slot,
855 private_data_name_id: AtomicU64::new(0),
856 private_data_metadata: Mutex::new(Default::default()),
857 }),
858 physical: Box::new(physical_device),
859 },
860 })
861 }
862
863 #[profiling::function]
865 pub fn try_from_display(
866 display: impl HasDisplayHandle,
867 info: impl Into<DeviceInfo>,
868 ) -> Result<Self, DriverError> {
869 let DeviceInfo {
870 debug,
871 physical_device_index,
872 } = info.into();
873 let instance_info = InstanceInfoBuilder::default().debug(debug);
874 let instance = Instance::try_from_display(display, instance_info)?;
875 let physical_device = select_physical_device(&instance, physical_device_index)?;
876
877 Self::try_from_physical_device(physical_device)
878 }
879
880 #[profiling::function]
882 pub fn try_from_physical_device(physical_device: PhysicalDevice) -> Result<Self, DriverError> {
883 let device = unsafe {
884 physical_device.create_ash_device(|device_create_info| {
885 physical_device.instance.create_device(
886 physical_device.handle,
887 &device_create_info,
888 None,
889 )
890 })
891 }
892 .map_err(|err| {
893 error!("unable to create device: {err}");
894
895 DriverError::Unsupported
896 })?;
897
898 info!("created {}", physical_device.properties_v1_0.device_name);
899
900 unsafe { Self::try_from_ash(device, physical_device) }
901 }
902
903 pub(crate) fn try_clear_private_data_object_name<T>(
904 this: &Self,
905 object_type: vk::ObjectType,
906 object_handle: T,
907 ) where
908 T: vk::Handle + Copy,
909 {
910 let _ = Self::clear_private_data_object_name(this, object_type, object_handle);
911 }
912
913 pub fn try_set_debug_utils_object_name<T>(
917 this: &Self,
918 object_handle: T,
919 object_name: impl AsRef<str>,
920 ) where
921 T: vk::Handle + Copy,
922 {
923 let _ = Self::set_debug_utils_object_name(this, object_handle, object_name);
924 }
925
926 pub(crate) fn try_set_private_data_object_name<T>(
930 this: &Self,
931 object_type: vk::ObjectType,
932 object_handle: T,
933 object_name: impl AsRef<str>,
934 ) where
935 T: vk::Handle + Copy,
936 {
937 let _ = Self::set_private_data_object_name(this, object_type, object_handle, object_name);
938 }
939
940 fn try_vk_ext_debug_utils(this: &Self) -> Result<&ext::debug_utils::Device, DriverError> {
941 this.inner
942 .vk_ext_debug_utils
943 .as_ref()
944 .ok_or(DriverError::Unsupported)
945 }
946
947 fn try_vk_ext_private_data(this: &Self) -> Result<&ext::private_data::Device, DriverError> {
948 this.inner
949 .vk_ext_private_data
950 .as_ref()
951 .ok_or(DriverError::Unsupported)
952 }
953
954 #[profiling::function]
956 pub(crate) fn wait_for_fence(this: &Self, fence: &vk::Fence) -> Result<(), DriverError> {
957 Device::wait_for_fences(this, slice::from_ref(fence))
958 }
959
960 #[profiling::function]
965 pub(crate) fn wait_for_fences(this: &Self, fences: &[vk::Fence]) -> Result<(), DriverError> {
966 unsafe {
967 match this.wait_for_fences(fences, true, 100) {
968 Ok(_) => return Ok(()),
969 Err(err) if err == vk::Result::ERROR_DEVICE_LOST => {
970 error!("invalid device state: lost");
971
972 return Err(DriverError::InvalidData);
973 }
974 Err(err) if err == vk::Result::TIMEOUT => {
975 trace!("waiting...");
976 }
977 Err(err) => {
978 warn!("unable to wait for fences during polling phase: {err}");
979
980 return Err(DriverError::OutOfMemory);
981 }
982 }
983
984 let started = cfg!(debug_assertions).then(Instant::now);
985
986 match this.wait_for_fences(fences, true, u64::MAX) {
987 Ok(_) => (),
988 Err(err) if err == vk::Result::ERROR_DEVICE_LOST => {
989 error!("invalid device state: lost");
990
991 return Err(DriverError::InvalidData);
992 }
993 Err(err) => {
994 warn!("unable to wait for fences to completion: {err}");
995
996 return Err(DriverError::OutOfMemory);
997 }
998 }
999
1000 if let Some(started) = started {
1001 let elapsed = Instant::now() - started;
1002 let elapsed_millis = elapsed.as_millis();
1003
1004 if elapsed_millis > 0 {
1005 warn!("slow fence wait: {} ms", elapsed_millis);
1006 }
1007 }
1008 }
1009
1010 Ok(())
1011 }
1012
1013 pub fn wait_idle(this: &Self) -> Result<(), DriverError> {
1015 unsafe {
1016 this.device_wait_idle().map_err(|err| {
1017 warn!("unable to wait for device idle: {err}");
1018
1019 match err {
1020 vk::Result::ERROR_OUT_OF_DEVICE_MEMORY
1021 | vk::Result::ERROR_OUT_OF_HOST_MEMORY => DriverError::OutOfMemory,
1022 vk::Result::ERROR_DEVICE_LOST | vk::Result::ERROR_VALIDATION_FAILED_EXT => {
1023 DriverError::InvalidData
1024 }
1025 _ => DriverError::Unsupported,
1026 }
1027 })
1028 }
1029 }
1030
1031 pub(crate) fn with_allocator<R>(this: &Self, f: impl FnOnce(&mut Allocator) -> R) -> R {
1033 let allocator = this.inner.allocator.lock();
1034
1035 #[cfg(not(feature = "parking_lot"))]
1036 let allocator = allocator.expect("poisoned allocator lock");
1037
1038 let mut allocator = allocator;
1039
1040 f(&mut allocator)
1041 }
1042
1043 fn with_object_metadata_ids<R>(
1044 this: &Self,
1045 f: impl FnOnce(&mut HashMap<(vk::ObjectType, u64), u64>) -> R,
1046 ) -> R {
1047 Self::with_private_data_metadata(this, |metadata| f(&mut metadata.object_metadata_ids))
1048 }
1049
1050 fn with_private_data_metadata<R>(
1051 this: &Self,
1052 f: impl FnOnce(&mut PrivateDataMetadata) -> R,
1053 ) -> R {
1054 let mut metadata = this.inner.private_data_metadata.lock();
1055
1056 #[cfg(not(feature = "parking_lot"))]
1057 let mut metadata = metadata.expect("poisoned private data metadata");
1058
1059 f(&mut metadata)
1060 }
1061
1062 pub fn with_queue<R>(
1071 this: &Self,
1072 queue_family_index: u32,
1073 queue_index: u32,
1074 f: impl FnOnce(vk::Queue) -> R,
1075 ) -> R {
1076 let queue_family = this
1077 .inner
1078 .queues
1079 .get(queue_family_index as usize)
1080 .expect("invalid queue family index");
1081 let queue = queue_family
1082 .get(queue_index as usize)
1083 .expect("invalid queue index");
1084 #[cfg(not(feature = "parking_lot"))]
1085 let guard = queue.lock().expect("poisoned queue lock");
1086
1087 #[cfg(feature = "parking_lot")]
1088 let guard = queue.lock();
1089
1090 f(*guard)
1091 }
1092}
1093
1094impl Debug for Device {
1095 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1096 f.debug_struct(stringify!(Device))
1097 .field("handle", &self.inner.device.handle())
1098 .field("physical", &self.physical)
1099 .finish_non_exhaustive()
1100 }
1101}
1102
1103#[cfg(doc)]
1104impl Deref for Device {
1105 type Target = ash::Device;
1106
1107 fn deref(&self) -> &Self::Target {
1108 unreachable!()
1109 }
1110}
1111
1112impl Eq for Device {}
1113
1114impl PartialEq for Device {
1115 fn eq(&self, other: &Self) -> bool {
1116 Arc::ptr_eq(&self.inner, &other.inner)
1117 }
1118}
1119
1120#[derive(Builder, Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
1122#[builder(
1123 build_fn(private, name = "fallible_build"),
1124 derive(Clone, Copy, Debug),
1125 pattern = "owned"
1126)]
1127pub struct DeviceInfo {
1128 #[builder(default)]
1147 pub debug: bool,
1148
1149 #[builder(default)]
1152 pub physical_device_index: usize,
1153}
1154
1155impl DeviceInfo {
1156 pub fn builder() -> DeviceInfoBuilder {
1158 Default::default()
1159 }
1160
1161 pub fn into_builder(self) -> DeviceInfoBuilder {
1163 DeviceInfoBuilder {
1164 debug: Some(self.debug),
1165 physical_device_index: Some(self.physical_device_index),
1166 }
1167 }
1168}
1169
1170impl From<DeviceInfoBuilder> for DeviceInfo {
1171 fn from(info: DeviceInfoBuilder) -> Self {
1172 info.build()
1173 }
1174}
1175
1176impl DeviceInfoBuilder {
1177 #[inline(always)]
1179 pub fn build(self) -> DeviceInfo {
1180 self.fallible_build().expect("invalid device info")
1181 }
1182}
1183
1184struct DeviceInner {
1185 allocator: ManuallyDrop<Mutex<Allocator>>,
1186 device: ash::Device,
1187 pipeline_cache: vk::PipelineCache,
1188 queues: Box<[Box<[Mutex<vk::Queue>]>]>,
1189 vk_ext_debug_utils: Option<ext::debug_utils::Device>,
1190 vk_ext_private_data: Option<ext::private_data::Device>,
1191 vk_khr_acceleration_structure: Option<khr::acceleration_structure::Device>,
1192 vk_khr_present_wait: Option<khr::present_wait::Device>,
1193 vk_khr_ray_tracing_pipeline: Option<khr::ray_tracing_pipeline::Device>,
1194 vk_khr_surface: Option<khr::surface::Instance>,
1195 vk_khr_swapchain: Option<khr::swapchain::Device>,
1196 vk_khr_synchronization2: Option<khr::synchronization2::Device>,
1197 private_data_slot: Option<vk::PrivateDataSlot>,
1198 private_data_name_id: AtomicU64,
1199 private_data_metadata: Mutex<PrivateDataMetadata>,
1200}
1201
1202#[derive(Default)]
1203struct PrivateDataMetadata {
1204 object_metadata_ids: HashMap<(vk::ObjectType, u64), u64>,
1205 names: HashMap<u64, String>,
1206}
1207
1208impl Drop for DeviceInner {
1209 #[profiling::function]
1210 fn drop(&mut self) {
1211 if panicking() {
1212 unsafe {
1214 forget(ManuallyDrop::take(&mut self.allocator));
1215 }
1216
1217 return;
1218 }
1219
1220 if let Err(err) = unsafe { self.device.device_wait_idle() } {
1223 warn!("device_wait_idle() failed: {err}");
1224 }
1225
1226 unsafe {
1227 self.device
1228 .destroy_pipeline_cache(self.pipeline_cache, None);
1229
1230 if let (Some(vk_ext_private_data), Some(private_data_slot)) = (
1231 self.vk_ext_private_data.as_ref(),
1232 self.private_data_slot.take(),
1233 ) {
1234 vk_ext_private_data.destroy_private_data_slot(private_data_slot, None);
1235 }
1236
1237 ManuallyDrop::drop(&mut self.allocator);
1238 }
1239
1240 unsafe {
1241 self.device.destroy_device(None);
1242 }
1243 }
1244}
1245
1246#[doc(hidden)]
1247impl Clone for ReadOnlyDevice {
1248 fn clone(&self) -> Self {
1249 Self {
1250 inner: self.inner.clone(),
1251 physical: self.physical.clone(),
1252 }
1253 }
1254}
1255
1256#[doc(hidden)]
1257impl Deref for ReadOnlyDevice {
1258 type Target = ash::Device;
1259
1260 fn deref(&self) -> &Self::Target {
1261 &self.inner.device
1262 }
1263}
1264
1265#[cfg(test)]
1266mod test {
1267 use super::*;
1268
1269 type Info = DeviceInfo;
1270 type Builder = DeviceInfoBuilder;
1271
1272 #[test]
1273 pub fn device_info() {
1274 Info::default().into_builder().build();
1275 }
1276
1277 #[test]
1278 pub fn device_info_builder() {
1279 Builder::default().build();
1280 }
1281}