1use alloc::{borrow::ToOwned as _, boxed::Box, ffi::CString, string::String, sync::Arc, vec::Vec};
2use core::{
3 ffi::{c_void, CStr},
4 marker::PhantomData,
5 slice,
6 str::FromStr,
7};
8use std::thread;
9
10use arrayvec::ArrayVec;
11use ash::{ext, khr, vk};
12use parking_lot::RwLock;
13
14unsafe extern "system" fn debug_utils_messenger_callback(
15 message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
16 message_type: vk::DebugUtilsMessageTypeFlagsEXT,
17 callback_data_ptr: *const vk::DebugUtilsMessengerCallbackDataEXT,
18 user_data: *mut c_void,
19) -> vk::Bool32 {
20 use alloc::borrow::Cow;
21
22 if thread::panicking() {
23 return vk::FALSE;
24 }
25
26 let cd = unsafe { &*callback_data_ptr };
27 let user_data = unsafe { &*user_data.cast::<super::DebugUtilsMessengerUserData>() };
28
29 const VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912: i32 = 0x56146426;
30 if cd.message_id_number == VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912 {
31 if let Some(layer_properties) = user_data.validation_layer_properties.as_ref() {
35 if layer_properties.layer_description.as_ref() == c"Khronos Validation Layer"
36 && layer_properties.layer_spec_version >= vk::make_api_version(0, 1, 3, 240)
37 && layer_properties.layer_spec_version <= vk::make_api_version(0, 1, 3, 250)
38 {
39 return vk::FALSE;
40 }
41 }
42 }
43
44 const VUID_VKSWAPCHAINCREATEINFOKHR_PNEXT_07781: i32 = 0x4c8929c1;
48 if cd.message_id_number == VUID_VKSWAPCHAINCREATEINFOKHR_PNEXT_07781 {
49 return vk::FALSE;
50 }
51
52 const VUID_VKRENDERPASSBEGININFO_FRAMEBUFFER_04627: i32 = 0x45125641;
59 if cd.message_id_number == VUID_VKRENDERPASSBEGININFO_FRAMEBUFFER_04627
60 && user_data.has_obs_layer
61 {
62 return vk::FALSE;
63 }
64
65 const VUID_VKCMDCOPYIMAGETOBUFFER_PREGIONS_00184: i32 = 0x45ef177c;
69 if cd.message_id_number == VUID_VKCMDCOPYIMAGETOBUFFER_PREGIONS_00184 {
70 return vk::FALSE;
71 }
72
73 const VUID_STANDALONESPIRV_NONE_10684: i32 = 0xb210f7c2_u32 as i32;
78 if cd.message_id_number == VUID_STANDALONESPIRV_NONE_10684 {
79 return vk::FALSE;
80 }
81
82 let level = match message_severity {
83 vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => log::Level::Debug,
84 vk::DebugUtilsMessageSeverityFlagsEXT::INFO => log::Level::Info,
85 vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => log::Level::Warn,
86 vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => log::Level::Error,
87 _ => log::Level::Warn,
88 };
89
90 let message_id_name =
91 unsafe { cd.message_id_name_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
92 let message = unsafe { cd.message_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
93
94 let _ = std::panic::catch_unwind(|| {
95 log::log!(
96 level,
97 "{:?} [{} (0x{:x})]\n\t{}",
98 message_type,
99 message_id_name,
100 cd.message_id_number,
101 message,
102 );
103 });
104
105 if cd.queue_label_count != 0 {
106 let labels =
107 unsafe { slice::from_raw_parts(cd.p_queue_labels, cd.queue_label_count as usize) };
108 let names = labels
109 .iter()
110 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
111 .collect::<Vec<_>>();
112
113 let _ = std::panic::catch_unwind(|| {
114 log::log!(level, "\tqueues: {}", names.join(", "));
115 });
116 }
117
118 if cd.cmd_buf_label_count != 0 {
119 let labels =
120 unsafe { slice::from_raw_parts(cd.p_cmd_buf_labels, cd.cmd_buf_label_count as usize) };
121 let names = labels
122 .iter()
123 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
124 .collect::<Vec<_>>();
125
126 let _ = std::panic::catch_unwind(|| {
127 log::log!(level, "\tcommand buffers: {}", names.join(", "));
128 });
129 }
130
131 if cd.object_count != 0 {
132 let labels = unsafe { slice::from_raw_parts(cd.p_objects, cd.object_count as usize) };
133 let names = labels
135 .iter()
136 .map(|obj_info| {
137 let name = unsafe { obj_info.object_name_as_c_str() }
138 .map_or(Cow::Borrowed("?"), CStr::to_string_lossy);
139
140 format!(
141 "(type: {:?}, hndl: 0x{:x}, name: {})",
142 obj_info.object_type, obj_info.object_handle, name
143 )
144 })
145 .collect::<Vec<_>>();
146 let _ = std::panic::catch_unwind(|| {
147 log::log!(level, "\tobjects: {}", names.join(", "));
148 });
149 }
150
151 #[cfg(feature = "validation_canary")]
152 if cfg!(debug_assertions) && level == log::Level::Error {
153 use alloc::string::ToString as _;
154
155 crate::VALIDATION_CANARY.add(message.to_string());
157 }
158
159 vk::FALSE
160}
161
162impl super::DebugUtilsCreateInfo {
163 fn to_vk_create_info(&self) -> vk::DebugUtilsMessengerCreateInfoEXT<'_> {
164 let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*self.callback_data;
165 vk::DebugUtilsMessengerCreateInfoEXT::default()
166 .message_severity(self.severity)
167 .message_type(self.message_type)
168 .user_data(user_data_ptr as *mut _)
169 .pfn_user_callback(Some(debug_utils_messenger_callback))
170 }
171}
172
173impl super::Swapchain {
174 unsafe fn release_resources(mut self, device: &ash::Device) -> Self {
178 profiling::scope!("Swapchain::release_resources");
179 {
180 profiling::scope!("vkDeviceWaitIdle");
181 let _ = unsafe {
184 device
185 .device_wait_idle()
186 .map_err(super::map_host_device_oom_and_lost_err)
187 };
188 };
189
190 for semaphore in self.surface_semaphores.drain(..) {
192 let arc_removed = Arc::into_inner(semaphore).expect(
193 "Trying to destroy a SurfaceSemaphores that is still in use by a SurfaceTexture",
194 );
195 let mutex_removed = arc_removed.into_inner();
196
197 unsafe { mutex_removed.destroy(device) };
198 }
199
200 self
201 }
202}
203
204impl super::InstanceShared {
205 pub fn entry(&self) -> &ash::Entry {
206 &self.entry
207 }
208
209 pub fn raw_instance(&self) -> &ash::Instance {
210 &self.raw
211 }
212
213 pub fn instance_api_version(&self) -> u32 {
214 self.instance_api_version
215 }
216
217 pub fn extensions(&self) -> &[&'static CStr] {
218 &self.extensions[..]
219 }
220}
221
222impl super::Instance {
223 pub fn shared_instance(&self) -> &super::InstanceShared {
224 &self.shared
225 }
226
227 fn enumerate_instance_extension_properties(
228 entry: &ash::Entry,
229 layer_name: Option<&CStr>,
230 ) -> Result<Vec<vk::ExtensionProperties>, crate::InstanceError> {
231 let instance_extensions = {
232 profiling::scope!("vkEnumerateInstanceExtensionProperties");
233 unsafe { entry.enumerate_instance_extension_properties(layer_name) }
234 };
235 instance_extensions.map_err(|e| {
236 crate::InstanceError::with_source(
237 String::from("enumerate_instance_extension_properties() failed"),
238 e,
239 )
240 })
241 }
242
243 pub fn desired_extensions(
257 entry: &ash::Entry,
258 _instance_api_version: u32,
259 flags: wgt::InstanceFlags,
260 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
261 let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?;
262
263 let mut extensions: Vec<&'static CStr> = Vec::new();
265
266 extensions.push(khr::surface::NAME);
268
269 if cfg!(all(
271 unix,
272 not(target_os = "android"),
273 not(target_os = "macos")
274 )) {
275 extensions.push(khr::xlib_surface::NAME);
277 extensions.push(khr::xcb_surface::NAME);
279 extensions.push(khr::wayland_surface::NAME);
281 }
282 if cfg!(target_os = "android") {
283 extensions.push(khr::android_surface::NAME);
285 }
286 if cfg!(target_os = "windows") {
287 extensions.push(khr::win32_surface::NAME);
289 }
290 if cfg!(target_os = "macos") {
291 extensions.push(ext::metal_surface::NAME);
293 extensions.push(khr::portability_enumeration::NAME);
294 }
295 if cfg!(all(
296 unix,
297 not(target_vendor = "apple"),
298 not(target_family = "wasm")
299 )) {
300 extensions.push(ext::acquire_drm_display::NAME);
302 extensions.push(ext::direct_mode_display::NAME);
303 extensions.push(khr::display::NAME);
304 extensions.push(ext::physical_device_drm::NAME);
306 extensions.push(khr::get_display_properties2::NAME);
307 }
308
309 if flags.contains(wgt::InstanceFlags::DEBUG) {
310 extensions.push(ext::debug_utils::NAME);
312 }
313
314 extensions.push(ext::swapchain_colorspace::NAME);
317
318 extensions.push(khr::get_physical_device_properties2::NAME);
322
323 extensions.retain(|&ext| {
325 if instance_extensions
326 .iter()
327 .any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext))
328 {
329 true
330 } else {
331 log::warn!("Unable to find extension: {}", ext.to_string_lossy());
332 false
333 }
334 });
335 Ok(extensions)
336 }
337
338 #[allow(clippy::too_many_arguments)]
351 pub unsafe fn from_raw(
352 entry: ash::Entry,
353 raw_instance: ash::Instance,
354 instance_api_version: u32,
355 android_sdk_version: u32,
356 debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
357 extensions: Vec<&'static CStr>,
358 flags: wgt::InstanceFlags,
359 memory_budget_thresholds: wgt::MemoryBudgetThresholds,
360 has_nv_optimus: bool,
361 drop_callback: Option<crate::DropCallback>,
362 ) -> Result<Self, crate::InstanceError> {
363 log::debug!("Instance version: 0x{:x}", instance_api_version);
364
365 let debug_utils = if let Some(debug_utils_create_info) = debug_utils_create_info {
366 if extensions.contains(&ext::debug_utils::NAME) {
367 log::info!("Enabling debug utils");
368
369 let extension = ext::debug_utils::Instance::new(&entry, &raw_instance);
370 let vk_info = debug_utils_create_info.to_vk_create_info();
371 let messenger =
372 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
373
374 Some(super::DebugUtils {
375 extension,
376 messenger,
377 callback_data: debug_utils_create_info.callback_data,
378 })
379 } else {
380 log::debug!("Debug utils not enabled: extension not listed");
381 None
382 }
383 } else {
384 log::debug!(
385 "Debug utils not enabled: \
386 debug_utils_user_data not passed to Instance::from_raw"
387 );
388 None
389 };
390
391 let get_physical_device_properties =
392 if extensions.contains(&khr::get_physical_device_properties2::NAME) {
393 log::debug!("Enabling device properties2");
394 Some(khr::get_physical_device_properties2::Instance::new(
395 &entry,
396 &raw_instance,
397 ))
398 } else {
399 None
400 };
401
402 let drop_guard = crate::DropGuard::from_option(drop_callback);
403
404 Ok(Self {
405 shared: Arc::new(super::InstanceShared {
406 raw: raw_instance,
407 extensions,
408 drop_guard,
409 flags,
410 memory_budget_thresholds,
411 debug_utils,
412 get_physical_device_properties,
413 entry,
414 has_nv_optimus,
415 instance_api_version,
416 android_sdk_version,
417 }),
418 })
419 }
420
421 fn create_surface_from_xlib(
422 &self,
423 dpy: *mut vk::Display,
424 window: vk::Window,
425 ) -> Result<super::Surface, crate::InstanceError> {
426 if !self.shared.extensions.contains(&khr::xlib_surface::NAME) {
427 return Err(crate::InstanceError::new(String::from(
428 "Vulkan driver does not support VK_KHR_xlib_surface",
429 )));
430 }
431
432 let surface = {
433 let xlib_loader =
434 khr::xlib_surface::Instance::new(&self.shared.entry, &self.shared.raw);
435 let info = vk::XlibSurfaceCreateInfoKHR::default()
436 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
437 .window(window)
438 .dpy(dpy);
439
440 unsafe { xlib_loader.create_xlib_surface(&info, None) }
441 .expect("XlibSurface::create_xlib_surface() failed")
442 };
443
444 Ok(self.create_surface_from_vk_surface_khr(surface))
445 }
446
447 fn create_surface_from_xcb(
448 &self,
449 connection: *mut vk::xcb_connection_t,
450 window: vk::xcb_window_t,
451 ) -> Result<super::Surface, crate::InstanceError> {
452 if !self.shared.extensions.contains(&khr::xcb_surface::NAME) {
453 return Err(crate::InstanceError::new(String::from(
454 "Vulkan driver does not support VK_KHR_xcb_surface",
455 )));
456 }
457
458 let surface = {
459 let xcb_loader = khr::xcb_surface::Instance::new(&self.shared.entry, &self.shared.raw);
460 let info = vk::XcbSurfaceCreateInfoKHR::default()
461 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
462 .window(window)
463 .connection(connection);
464
465 unsafe { xcb_loader.create_xcb_surface(&info, None) }
466 .expect("XcbSurface::create_xcb_surface() failed")
467 };
468
469 Ok(self.create_surface_from_vk_surface_khr(surface))
470 }
471
472 fn create_surface_from_wayland(
473 &self,
474 display: *mut vk::wl_display,
475 surface: *mut vk::wl_surface,
476 ) -> Result<super::Surface, crate::InstanceError> {
477 if !self.shared.extensions.contains(&khr::wayland_surface::NAME) {
478 return Err(crate::InstanceError::new(String::from(
479 "Vulkan driver does not support VK_KHR_wayland_surface",
480 )));
481 }
482
483 let surface = {
484 let w_loader =
485 khr::wayland_surface::Instance::new(&self.shared.entry, &self.shared.raw);
486 let info = vk::WaylandSurfaceCreateInfoKHR::default()
487 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
488 .display(display)
489 .surface(surface);
490
491 unsafe { w_loader.create_wayland_surface(&info, None) }.expect("WaylandSurface failed")
492 };
493
494 Ok(self.create_surface_from_vk_surface_khr(surface))
495 }
496
497 fn create_surface_android(
498 &self,
499 window: *mut vk::ANativeWindow,
500 ) -> Result<super::Surface, crate::InstanceError> {
501 if !self.shared.extensions.contains(&khr::android_surface::NAME) {
502 return Err(crate::InstanceError::new(String::from(
503 "Vulkan driver does not support VK_KHR_android_surface",
504 )));
505 }
506
507 let surface = {
508 let a_loader =
509 khr::android_surface::Instance::new(&self.shared.entry, &self.shared.raw);
510 let info = vk::AndroidSurfaceCreateInfoKHR::default()
511 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
512 .window(window);
513
514 unsafe { a_loader.create_android_surface(&info, None) }.expect("AndroidSurface failed")
515 };
516
517 Ok(self.create_surface_from_vk_surface_khr(surface))
518 }
519
520 fn create_surface_from_hwnd(
521 &self,
522 hinstance: vk::HINSTANCE,
523 hwnd: vk::HWND,
524 ) -> Result<super::Surface, crate::InstanceError> {
525 if !self.shared.extensions.contains(&khr::win32_surface::NAME) {
526 return Err(crate::InstanceError::new(String::from(
527 "Vulkan driver does not support VK_KHR_win32_surface",
528 )));
529 }
530
531 let surface = {
532 let info = vk::Win32SurfaceCreateInfoKHR::default()
533 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
534 .hinstance(hinstance)
535 .hwnd(hwnd);
536 let win32_loader =
537 khr::win32_surface::Instance::new(&self.shared.entry, &self.shared.raw);
538 unsafe {
539 win32_loader
540 .create_win32_surface(&info, None)
541 .expect("Unable to create Win32 surface")
542 }
543 };
544
545 Ok(self.create_surface_from_vk_surface_khr(surface))
546 }
547
548 #[cfg(metal)]
549 fn create_surface_from_view(
550 &self,
551 view: core::ptr::NonNull<c_void>,
552 ) -> Result<super::Surface, crate::InstanceError> {
553 if !self.shared.extensions.contains(&ext::metal_surface::NAME) {
554 return Err(crate::InstanceError::new(String::from(
555 "Vulkan driver does not support VK_EXT_metal_surface",
556 )));
557 }
558
559 let layer = unsafe { crate::metal::Surface::get_metal_layer(view.cast()) };
560 let layer_ptr = (*layer).cast();
563
564 let surface = {
565 let metal_loader =
566 ext::metal_surface::Instance::new(&self.shared.entry, &self.shared.raw);
567 let vk_info = vk::MetalSurfaceCreateInfoEXT::default()
568 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
569 .layer(layer_ptr);
570
571 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
572 };
573
574 Ok(self.create_surface_from_vk_surface_khr(surface))
575 }
576
577 pub(super) fn create_surface_from_vk_surface_khr(
578 &self,
579 surface: vk::SurfaceKHR,
580 ) -> super::Surface {
581 let functor = khr::surface::Instance::new(&self.shared.entry, &self.shared.raw);
582 super::Surface {
583 raw: surface,
584 functor,
585 instance: Arc::clone(&self.shared),
586 swapchain: RwLock::new(None),
587 }
588 }
589
590 pub unsafe fn init_with_callback(
599 desc: &crate::InstanceDescriptor,
600 callback: Option<Box<super::CreateInstanceCallback>>,
601 ) -> Result<Self, crate::InstanceError> {
602 profiling::scope!("Init Vulkan Backend");
603
604 let entry = unsafe {
605 profiling::scope!("Load vk library");
606 ash::Entry::load()
607 }
608 .map_err(|err| {
609 crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
610 })?;
611 let version = {
612 profiling::scope!("vkEnumerateInstanceVersion");
613 unsafe { entry.try_enumerate_instance_version() }
614 };
615 let instance_api_version = match version {
616 Ok(Some(version)) => version,
618 Ok(None) => vk::API_VERSION_1_0,
619 Err(err) => {
620 return Err(crate::InstanceError::with_source(
621 String::from("try_enumerate_instance_version() failed"),
622 err,
623 ));
624 }
625 };
626
627 let app_name = CString::new(desc.name).unwrap();
628 let app_info = vk::ApplicationInfo::default()
629 .application_name(app_name.as_c_str())
630 .application_version(1)
631 .engine_name(c"wgpu-hal")
632 .engine_version(2)
633 .api_version(
634 if instance_api_version < vk::API_VERSION_1_1 {
636 vk::API_VERSION_1_0
637 } else {
638 vk::API_VERSION_1_3
647 },
648 );
649
650 let mut extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
651 let mut create_info = vk::InstanceCreateInfo::default();
652
653 if let Some(callback) = callback {
654 callback(super::CreateInstanceCallbackArgs {
655 extensions: &mut extensions,
656 create_info: &mut create_info,
657 entry: &entry,
658 _phantom: PhantomData,
659 });
660 }
661
662 let instance_layers = {
663 profiling::scope!("vkEnumerateInstanceLayerProperties");
664 unsafe { entry.enumerate_instance_layer_properties() }
665 };
666 let instance_layers = instance_layers.map_err(|e| {
667 log::debug!("enumerate_instance_layer_properties: {:?}", e);
668 crate::InstanceError::with_source(
669 String::from("enumerate_instance_layer_properties() failed"),
670 e,
671 )
672 })?;
673
674 fn find_layer<'layers>(
675 instance_layers: &'layers [vk::LayerProperties],
676 name: &CStr,
677 ) -> Option<&'layers vk::LayerProperties> {
678 instance_layers
679 .iter()
680 .find(|inst_layer| inst_layer.layer_name_as_c_str() == Ok(name))
681 }
682
683 let validation_layer_name = c"VK_LAYER_KHRONOS_validation";
684 let validation_layer_properties = find_layer(&instance_layers, validation_layer_name);
685
686 let validation_features_are_enabled = if validation_layer_properties.is_some() {
689 let exts =
691 Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?;
692 let mut ext_names = exts
694 .iter()
695 .filter_map(|ext| ext.extension_name_as_c_str().ok());
696 ext_names.any(|ext_name| ext_name == ext::validation_features::NAME)
698 } else {
699 false
700 };
701
702 let should_enable_gpu_based_validation = desc
703 .flags
704 .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
705 && validation_features_are_enabled;
706
707 let has_nv_optimus = find_layer(&instance_layers, c"VK_LAYER_NV_optimus").is_some();
708
709 let has_obs_layer = find_layer(&instance_layers, c"VK_LAYER_OBS_HOOK").is_some();
710
711 let mut layers: Vec<&'static CStr> = Vec::new();
712
713 let has_debug_extension = extensions.contains(&ext::debug_utils::NAME);
714 let mut debug_user_data = has_debug_extension.then(|| {
715 Box::new(super::DebugUtilsMessengerUserData {
718 validation_layer_properties: None,
719 has_obs_layer,
720 })
721 });
722
723 if desc.flags.intersects(wgt::InstanceFlags::VALIDATION)
725 || should_enable_gpu_based_validation
726 {
727 if let Some(layer_properties) = validation_layer_properties {
728 layers.push(validation_layer_name);
729
730 if let Some(debug_user_data) = debug_user_data.as_mut() {
731 debug_user_data.validation_layer_properties =
732 Some(super::ValidationLayerProperties {
733 layer_description: layer_properties
734 .description_as_c_str()
735 .unwrap()
736 .to_owned(),
737 layer_spec_version: layer_properties.spec_version,
738 });
739 }
740 } else {
741 log::warn!(
742 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
743 validation_layer_name.to_string_lossy()
744 );
745 }
746 }
747 let mut debug_utils = if let Some(callback_data) = debug_user_data {
748 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
750 if log::max_level() >= log::LevelFilter::Debug {
751 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
752 }
753 if log::max_level() >= log::LevelFilter::Info {
754 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
755 }
756 if log::max_level() >= log::LevelFilter::Warn {
757 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
758 }
759
760 let message_type = vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
761 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
762 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
763
764 let create_info = super::DebugUtilsCreateInfo {
765 severity,
766 message_type,
767 callback_data,
768 };
769
770 Some(create_info)
771 } else {
772 None
773 };
774
775 #[cfg(target_os = "android")]
776 let android_sdk_version = {
777 let properties = android_system_properties::AndroidSystemProperties::new();
778 if let Some(val) = properties.get("ro.build.version.sdk") {
780 match val.parse::<u32>() {
781 Ok(sdk_ver) => sdk_ver,
782 Err(err) => {
783 log::error!(
784 concat!(
785 "Couldn't parse Android's ",
786 "ro.build.version.sdk system property ({}): {}",
787 ),
788 val,
789 err,
790 );
791 0
792 }
793 }
794 } else {
795 log::error!("Couldn't read Android's ro.build.version.sdk system property");
796 0
797 }
798 };
799 #[cfg(not(target_os = "android"))]
800 let android_sdk_version = 0;
801
802 let mut flags = vk::InstanceCreateFlags::empty();
803
804 if extensions.contains(&khr::portability_enumeration::NAME) {
808 flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
809 }
810 let vk_instance = {
811 let str_pointers = layers
812 .iter()
813 .chain(extensions.iter())
814 .map(|&s: &&'static _| {
815 s.as_ptr()
817 })
818 .collect::<Vec<_>>();
819
820 create_info = create_info
821 .flags(flags)
822 .application_info(&app_info)
823 .enabled_layer_names(&str_pointers[..layers.len()])
824 .enabled_extension_names(&str_pointers[layers.len()..]);
825
826 let mut debug_utils_create_info = debug_utils
827 .as_mut()
828 .map(|create_info| create_info.to_vk_create_info());
829 if let Some(debug_utils_create_info) = debug_utils_create_info.as_mut() {
830 create_info = create_info.push_next(debug_utils_create_info);
831 }
832
833 let mut validation_features;
835 let mut validation_feature_list: ArrayVec<_, 3>;
836 if validation_features_are_enabled {
837 validation_feature_list = ArrayVec::new();
838
839 validation_feature_list
841 .push(vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION);
842
843 if should_enable_gpu_based_validation {
845 validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED);
846 validation_feature_list
847 .push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT);
848 }
849
850 validation_features = vk::ValidationFeaturesEXT::default()
851 .enabled_validation_features(&validation_feature_list);
852 create_info = create_info.push_next(&mut validation_features);
853 }
854
855 unsafe {
856 profiling::scope!("vkCreateInstance");
857 entry.create_instance(&create_info, None)
858 }
859 .map_err(|e| {
860 crate::InstanceError::with_source(
861 String::from("Entry::create_instance() failed"),
862 e,
863 )
864 })?
865 };
866
867 unsafe {
868 Self::from_raw(
869 entry,
870 vk_instance,
871 instance_api_version,
872 android_sdk_version,
873 debug_utils,
874 extensions,
875 desc.flags,
876 desc.memory_budget_thresholds,
877 has_nv_optimus,
878 None,
879 )
880 }
881 }
882}
883
884impl Drop for super::InstanceShared {
885 fn drop(&mut self) {
886 unsafe {
887 let _du = self.debug_utils.take().inspect(|du| {
889 du.extension
890 .destroy_debug_utils_messenger(du.messenger, None);
891 });
892 if self.drop_guard.is_none() {
893 self.raw.destroy_instance(None);
894 }
895 }
896 }
897}
898
899impl crate::Instance for super::Instance {
900 type A = super::Api;
901
902 unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
903 unsafe { Self::init_with_callback(desc, None) }
904 }
905
906 unsafe fn create_surface(
907 &self,
908 display_handle: raw_window_handle::RawDisplayHandle,
909 window_handle: raw_window_handle::RawWindowHandle,
910 ) -> Result<super::Surface, crate::InstanceError> {
911 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
912
913 match (window_handle, display_handle) {
916 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
917 self.create_surface_from_wayland(display.display.as_ptr(), handle.surface.as_ptr())
918 }
919 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
920 let display = display.display.expect("Display pointer is not set.");
921 self.create_surface_from_xlib(display.as_ptr(), handle.window)
922 }
923 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
924 let connection = display.connection.expect("Pointer to X-Server is not set.");
925 self.create_surface_from_xcb(connection.as_ptr(), handle.window.get())
926 }
927 (Rwh::AndroidNdk(handle), _) => {
928 self.create_surface_android(handle.a_native_window.as_ptr())
929 }
930 (Rwh::Win32(handle), _) => {
931 let hinstance = handle.hinstance.ok_or_else(|| {
932 crate::InstanceError::new(String::from(
933 "Vulkan requires raw-window-handle's Win32::hinstance to be set",
934 ))
935 })?;
936 self.create_surface_from_hwnd(hinstance.get(), handle.hwnd.get())
937 }
938 #[cfg(all(target_os = "macos", feature = "metal"))]
939 (Rwh::AppKit(handle), _)
940 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
941 {
942 self.create_surface_from_view(handle.ns_view)
943 }
944 #[cfg(all(any(target_os = "ios", target_os = "visionos"), feature = "metal"))]
945 (Rwh::UiKit(handle), _)
946 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
947 {
948 self.create_surface_from_view(handle.ui_view)
949 }
950 (_, _) => Err(crate::InstanceError::new(format!(
951 "window handle {window_handle:?} is not a Vulkan-compatible handle"
952 ))),
953 }
954 }
955
956 unsafe fn enumerate_adapters(
957 &self,
958 _surface_hint: Option<&super::Surface>,
959 ) -> Vec<crate::ExposedAdapter<super::Api>> {
960 use crate::auxil::db;
961
962 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
963 Ok(devices) => devices,
964 Err(err) => {
965 log::error!("enumerate_adapters: {}", err);
966 Vec::new()
967 }
968 };
969
970 let mut exposed_adapters = raw_devices
971 .into_iter()
972 .flat_map(|device| self.expose_adapter(device))
973 .collect::<Vec<_>>();
974
975 let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| {
977 exposed.info.device_type == wgt::DeviceType::DiscreteGpu
978 && exposed.info.vendor == db::nvidia::VENDOR
979 });
980 if cfg!(target_os = "linux") && has_nvidia_dgpu && self.shared.has_nv_optimus {
981 for exposed in exposed_adapters.iter_mut() {
982 if exposed.info.device_type == wgt::DeviceType::IntegratedGpu
983 && exposed.info.vendor == db::intel::VENDOR
984 {
985 if let Some(version) = exposed.info.driver_info.split_once("Mesa ").map(|s| {
987 let mut components = s.1.split('.');
988 let major = components.next().and_then(|s| u8::from_str(s).ok());
989 let minor = components.next().and_then(|s| u8::from_str(s).ok());
990 if let (Some(major), Some(minor)) = (major, minor) {
991 (major, minor)
992 } else {
993 (0, 0)
994 }
995 }) {
996 if version < (21, 2) {
997 log::warn!(
999 concat!(
1000 "Disabling presentation on '{}' (id {:?}) ",
1001 "due to NV Optimus and Intel Mesa < v21.2"
1002 ),
1003 exposed.info.name,
1004 exposed.adapter.raw
1005 );
1006 exposed.adapter.private_caps.can_present = false;
1007 }
1008 }
1009 }
1010 }
1011 }
1012
1013 exposed_adapters
1014 }
1015}
1016
1017impl Drop for super::Surface {
1018 fn drop(&mut self) {
1019 unsafe { self.functor.destroy_surface(self.raw, None) };
1020 }
1021}
1022
1023impl crate::Surface for super::Surface {
1024 type A = super::Api;
1025
1026 unsafe fn configure(
1027 &self,
1028 device: &super::Device,
1029 config: &crate::SurfaceConfiguration,
1030 ) -> Result<(), crate::SurfaceError> {
1031 let mut swap_chain = self.swapchain.write();
1033 let old = swap_chain
1034 .take()
1035 .map(|sc| unsafe { sc.release_resources(&device.shared.raw) });
1036
1037 let swapchain = unsafe { device.create_swapchain(self, config, old)? };
1038 *swap_chain = Some(swapchain);
1039
1040 Ok(())
1041 }
1042
1043 unsafe fn unconfigure(&self, device: &super::Device) {
1044 if let Some(sc) = self.swapchain.write().take() {
1045 let swapchain = unsafe { sc.release_resources(&device.shared.raw) };
1047 unsafe { swapchain.functor.destroy_swapchain(swapchain.raw, None) };
1048 }
1049 }
1050
1051 unsafe fn acquire_texture(
1052 &self,
1053 timeout: Option<core::time::Duration>,
1054 fence: &super::Fence,
1055 ) -> Result<Option<crate::AcquiredSurfaceTexture<super::Api>>, crate::SurfaceError> {
1056 let mut swapchain = self.swapchain.write();
1057 let swapchain = swapchain.as_mut().unwrap();
1058
1059 let mut timeout_ns = match timeout {
1060 Some(duration) => duration.as_nanos() as u64,
1061 None => u64::MAX,
1062 };
1063
1064 if cfg!(target_os = "android") && self.instance.android_sdk_version < 30 {
1074 timeout_ns = u64::MAX;
1075 }
1076
1077 let swapchain_semaphores_arc = swapchain.get_surface_semaphores();
1078 let locked_swapchain_semaphores = swapchain_semaphores_arc
1080 .try_lock()
1081 .expect("Failed to lock a SwapchainSemaphores.");
1082
1083 swapchain.device.wait_for_fence(
1097 fence,
1098 locked_swapchain_semaphores.previously_used_submission_index,
1099 timeout_ns,
1100 )?;
1101
1102 let (index, suboptimal) = match unsafe {
1104 profiling::scope!("vkAcquireNextImageKHR");
1105 swapchain.functor.acquire_next_image(
1106 swapchain.raw,
1107 timeout_ns,
1108 locked_swapchain_semaphores.acquire,
1109 vk::Fence::null(),
1110 )
1111 } {
1112 #[cfg(target_os = "android")]
1115 Ok((index, _)) => (index, false),
1116 #[cfg(not(target_os = "android"))]
1117 Ok(pair) => pair,
1118 Err(error) => {
1119 return match error {
1120 vk::Result::TIMEOUT => Ok(None),
1121 vk::Result::NOT_READY | vk::Result::ERROR_OUT_OF_DATE_KHR => {
1122 Err(crate::SurfaceError::Outdated)
1123 }
1124 vk::Result::ERROR_SURFACE_LOST_KHR => Err(crate::SurfaceError::Lost),
1125 other => Err(super::map_host_device_oom_and_lost_err(other).into()),
1128 };
1129 }
1130 };
1131
1132 drop(locked_swapchain_semaphores);
1133 swapchain.advance_surface_semaphores();
1136
1137 if swapchain.device.vendor_id == crate::auxil::db::intel::VENDOR && index > 0x100 {
1139 return Err(crate::SurfaceError::Outdated);
1140 }
1141
1142 let texture = super::SurfaceTexture {
1143 index,
1144 texture: super::Texture {
1145 raw: swapchain.images[index as usize],
1146 drop_guard: None,
1147 block: None,
1148 external_memory: None,
1149 format: swapchain.config.format,
1150 copy_size: crate::CopyExtent {
1151 width: swapchain.config.extent.width,
1152 height: swapchain.config.extent.height,
1153 depth: 1,
1154 },
1155 },
1156 surface_semaphores: swapchain_semaphores_arc,
1157 };
1158 Ok(Some(crate::AcquiredSurfaceTexture {
1159 texture,
1160 suboptimal,
1161 }))
1162 }
1163
1164 unsafe fn discard_texture(&self, _texture: super::SurfaceTexture) {}
1165}