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.acquire_semaphores.drain(..) {
192 let arc_removed = Arc::into_inner(semaphore).expect(
193 "Trying to destroy a SurfaceAcquireSemaphores 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 for semaphore in self.present_semaphores.drain(..) {
201 let arc_removed = Arc::into_inner(semaphore).expect(
202 "Trying to destroy a SurfacePresentSemaphores that is still in use by a SurfaceTexture",
203 );
204 let mutex_removed = arc_removed.into_inner();
205
206 unsafe { mutex_removed.destroy(device) };
207 }
208
209 self
210 }
211}
212
213impl super::InstanceShared {
214 pub fn entry(&self) -> &ash::Entry {
215 &self.entry
216 }
217
218 pub fn raw_instance(&self) -> &ash::Instance {
219 &self.raw
220 }
221
222 pub fn instance_api_version(&self) -> u32 {
223 self.instance_api_version
224 }
225
226 pub fn extensions(&self) -> &[&'static CStr] {
227 &self.extensions[..]
228 }
229}
230
231impl super::Instance {
232 pub fn shared_instance(&self) -> &super::InstanceShared {
233 &self.shared
234 }
235
236 fn enumerate_instance_extension_properties(
237 entry: &ash::Entry,
238 layer_name: Option<&CStr>,
239 ) -> Result<Vec<vk::ExtensionProperties>, crate::InstanceError> {
240 let instance_extensions = {
241 profiling::scope!("vkEnumerateInstanceExtensionProperties");
242 unsafe { entry.enumerate_instance_extension_properties(layer_name) }
243 };
244 instance_extensions.map_err(|e| {
245 crate::InstanceError::with_source(
246 String::from("enumerate_instance_extension_properties() failed"),
247 e,
248 )
249 })
250 }
251
252 pub fn desired_extensions(
266 entry: &ash::Entry,
267 _instance_api_version: u32,
268 flags: wgt::InstanceFlags,
269 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
270 let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?;
271
272 let mut extensions: Vec<&'static CStr> = Vec::new();
274
275 extensions.push(khr::surface::NAME);
277
278 if cfg!(all(
280 unix,
281 not(target_os = "android"),
282 not(target_os = "macos")
283 )) {
284 extensions.push(khr::xlib_surface::NAME);
286 extensions.push(khr::xcb_surface::NAME);
288 extensions.push(khr::wayland_surface::NAME);
290 }
291 if cfg!(target_os = "android") {
292 extensions.push(khr::android_surface::NAME);
294 }
295 if cfg!(target_os = "windows") {
296 extensions.push(khr::win32_surface::NAME);
298 }
299 if cfg!(target_os = "macos") {
300 extensions.push(ext::metal_surface::NAME);
302 extensions.push(khr::portability_enumeration::NAME);
303 }
304 if cfg!(all(
305 unix,
306 not(target_vendor = "apple"),
307 not(target_family = "wasm")
308 )) {
309 extensions.push(ext::acquire_drm_display::NAME);
311 extensions.push(ext::direct_mode_display::NAME);
312 extensions.push(khr::display::NAME);
313 extensions.push(ext::physical_device_drm::NAME);
315 extensions.push(khr::get_display_properties2::NAME);
316 }
317
318 if flags.contains(wgt::InstanceFlags::DEBUG) {
319 extensions.push(ext::debug_utils::NAME);
321 }
322
323 extensions.push(ext::swapchain_colorspace::NAME);
326
327 extensions.push(khr::get_physical_device_properties2::NAME);
331
332 extensions.retain(|&ext| {
334 if instance_extensions
335 .iter()
336 .any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext))
337 {
338 true
339 } else {
340 log::warn!("Unable to find extension: {}", ext.to_string_lossy());
341 false
342 }
343 });
344 Ok(extensions)
345 }
346
347 #[allow(clippy::too_many_arguments)]
360 pub unsafe fn from_raw(
361 entry: ash::Entry,
362 raw_instance: ash::Instance,
363 instance_api_version: u32,
364 android_sdk_version: u32,
365 debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
366 extensions: Vec<&'static CStr>,
367 flags: wgt::InstanceFlags,
368 memory_budget_thresholds: wgt::MemoryBudgetThresholds,
369 has_nv_optimus: bool,
370 drop_callback: Option<crate::DropCallback>,
371 ) -> Result<Self, crate::InstanceError> {
372 log::debug!("Instance version: 0x{instance_api_version:x}");
373
374 let debug_utils = if let Some(debug_utils_create_info) = debug_utils_create_info {
375 if extensions.contains(&ext::debug_utils::NAME) {
376 log::info!("Enabling debug utils");
377
378 let extension = ext::debug_utils::Instance::new(&entry, &raw_instance);
379 let vk_info = debug_utils_create_info.to_vk_create_info();
380 let messenger =
381 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
382
383 Some(super::DebugUtils {
384 extension,
385 messenger,
386 callback_data: debug_utils_create_info.callback_data,
387 })
388 } else {
389 log::debug!("Debug utils not enabled: extension not listed");
390 None
391 }
392 } else {
393 log::debug!(
394 "Debug utils not enabled: \
395 debug_utils_user_data not passed to Instance::from_raw"
396 );
397 None
398 };
399
400 let get_physical_device_properties =
401 if extensions.contains(&khr::get_physical_device_properties2::NAME) {
402 log::debug!("Enabling device properties2");
403 Some(khr::get_physical_device_properties2::Instance::new(
404 &entry,
405 &raw_instance,
406 ))
407 } else {
408 None
409 };
410
411 let drop_guard = crate::DropGuard::from_option(drop_callback);
412
413 Ok(Self {
414 shared: Arc::new(super::InstanceShared {
415 raw: raw_instance,
416 extensions,
417 drop_guard,
418 flags,
419 memory_budget_thresholds,
420 debug_utils,
421 get_physical_device_properties,
422 entry,
423 has_nv_optimus,
424 instance_api_version,
425 android_sdk_version,
426 }),
427 })
428 }
429
430 fn create_surface_from_xlib(
431 &self,
432 dpy: *mut vk::Display,
433 window: vk::Window,
434 ) -> Result<super::Surface, crate::InstanceError> {
435 if !self.shared.extensions.contains(&khr::xlib_surface::NAME) {
436 return Err(crate::InstanceError::new(String::from(
437 "Vulkan driver does not support VK_KHR_xlib_surface",
438 )));
439 }
440
441 let surface = {
442 let xlib_loader =
443 khr::xlib_surface::Instance::new(&self.shared.entry, &self.shared.raw);
444 let info = vk::XlibSurfaceCreateInfoKHR::default()
445 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
446 .window(window)
447 .dpy(dpy);
448
449 unsafe { xlib_loader.create_xlib_surface(&info, None) }
450 .expect("XlibSurface::create_xlib_surface() failed")
451 };
452
453 Ok(self.create_surface_from_vk_surface_khr(surface))
454 }
455
456 fn create_surface_from_xcb(
457 &self,
458 connection: *mut vk::xcb_connection_t,
459 window: vk::xcb_window_t,
460 ) -> Result<super::Surface, crate::InstanceError> {
461 if !self.shared.extensions.contains(&khr::xcb_surface::NAME) {
462 return Err(crate::InstanceError::new(String::from(
463 "Vulkan driver does not support VK_KHR_xcb_surface",
464 )));
465 }
466
467 let surface = {
468 let xcb_loader = khr::xcb_surface::Instance::new(&self.shared.entry, &self.shared.raw);
469 let info = vk::XcbSurfaceCreateInfoKHR::default()
470 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
471 .window(window)
472 .connection(connection);
473
474 unsafe { xcb_loader.create_xcb_surface(&info, None) }
475 .expect("XcbSurface::create_xcb_surface() failed")
476 };
477
478 Ok(self.create_surface_from_vk_surface_khr(surface))
479 }
480
481 fn create_surface_from_wayland(
482 &self,
483 display: *mut vk::wl_display,
484 surface: *mut vk::wl_surface,
485 ) -> Result<super::Surface, crate::InstanceError> {
486 if !self.shared.extensions.contains(&khr::wayland_surface::NAME) {
487 return Err(crate::InstanceError::new(String::from(
488 "Vulkan driver does not support VK_KHR_wayland_surface",
489 )));
490 }
491
492 let surface = {
493 let w_loader =
494 khr::wayland_surface::Instance::new(&self.shared.entry, &self.shared.raw);
495 let info = vk::WaylandSurfaceCreateInfoKHR::default()
496 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
497 .display(display)
498 .surface(surface);
499
500 unsafe { w_loader.create_wayland_surface(&info, None) }.expect("WaylandSurface failed")
501 };
502
503 Ok(self.create_surface_from_vk_surface_khr(surface))
504 }
505
506 fn create_surface_android(
507 &self,
508 window: *mut vk::ANativeWindow,
509 ) -> Result<super::Surface, crate::InstanceError> {
510 if !self.shared.extensions.contains(&khr::android_surface::NAME) {
511 return Err(crate::InstanceError::new(String::from(
512 "Vulkan driver does not support VK_KHR_android_surface",
513 )));
514 }
515
516 let surface = {
517 let a_loader =
518 khr::android_surface::Instance::new(&self.shared.entry, &self.shared.raw);
519 let info = vk::AndroidSurfaceCreateInfoKHR::default()
520 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
521 .window(window);
522
523 unsafe { a_loader.create_android_surface(&info, None) }.expect("AndroidSurface failed")
524 };
525
526 Ok(self.create_surface_from_vk_surface_khr(surface))
527 }
528
529 fn create_surface_from_hwnd(
530 &self,
531 hinstance: vk::HINSTANCE,
532 hwnd: vk::HWND,
533 ) -> Result<super::Surface, crate::InstanceError> {
534 if !self.shared.extensions.contains(&khr::win32_surface::NAME) {
535 return Err(crate::InstanceError::new(String::from(
536 "Vulkan driver does not support VK_KHR_win32_surface",
537 )));
538 }
539
540 let surface = {
541 let info = vk::Win32SurfaceCreateInfoKHR::default()
542 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
543 .hinstance(hinstance)
544 .hwnd(hwnd);
545 let win32_loader =
546 khr::win32_surface::Instance::new(&self.shared.entry, &self.shared.raw);
547 unsafe {
548 win32_loader
549 .create_win32_surface(&info, None)
550 .expect("Unable to create Win32 surface")
551 }
552 };
553
554 Ok(self.create_surface_from_vk_surface_khr(surface))
555 }
556
557 #[cfg(metal)]
558 fn create_surface_from_view(
559 &self,
560 view: core::ptr::NonNull<c_void>,
561 ) -> Result<super::Surface, crate::InstanceError> {
562 if !self.shared.extensions.contains(&ext::metal_surface::NAME) {
563 return Err(crate::InstanceError::new(String::from(
564 "Vulkan driver does not support VK_EXT_metal_surface",
565 )));
566 }
567
568 let layer = unsafe { crate::metal::Surface::get_metal_layer(view.cast()) };
569 let layer_ptr = (*layer).cast();
572
573 let surface = {
574 let metal_loader =
575 ext::metal_surface::Instance::new(&self.shared.entry, &self.shared.raw);
576 let vk_info = vk::MetalSurfaceCreateInfoEXT::default()
577 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
578 .layer(layer_ptr);
579
580 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
581 };
582
583 Ok(self.create_surface_from_vk_surface_khr(surface))
584 }
585
586 pub(super) fn create_surface_from_vk_surface_khr(
587 &self,
588 surface: vk::SurfaceKHR,
589 ) -> super::Surface {
590 let functor = khr::surface::Instance::new(&self.shared.entry, &self.shared.raw);
591 super::Surface {
592 raw: surface,
593 functor,
594 instance: Arc::clone(&self.shared),
595 swapchain: RwLock::new(None),
596 }
597 }
598
599 pub unsafe fn init_with_callback(
608 desc: &crate::InstanceDescriptor,
609 callback: Option<Box<super::CreateInstanceCallback>>,
610 ) -> Result<Self, crate::InstanceError> {
611 profiling::scope!("Init Vulkan Backend");
612
613 let entry = unsafe {
614 profiling::scope!("Load vk library");
615 ash::Entry::load()
616 }
617 .map_err(|err| {
618 crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
619 })?;
620 let version = {
621 profiling::scope!("vkEnumerateInstanceVersion");
622 unsafe { entry.try_enumerate_instance_version() }
623 };
624 let instance_api_version = match version {
625 Ok(Some(version)) => version,
627 Ok(None) => vk::API_VERSION_1_0,
628 Err(err) => {
629 return Err(crate::InstanceError::with_source(
630 String::from("try_enumerate_instance_version() failed"),
631 err,
632 ));
633 }
634 };
635
636 let app_name = CString::new(desc.name).unwrap();
637 let app_info = vk::ApplicationInfo::default()
638 .application_name(app_name.as_c_str())
639 .application_version(1)
640 .engine_name(c"wgpu-hal")
641 .engine_version(2)
642 .api_version(
643 if instance_api_version < vk::API_VERSION_1_1 {
645 vk::API_VERSION_1_0
646 } else {
647 vk::API_VERSION_1_3
656 },
657 );
658
659 let mut extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
660 let mut create_info = vk::InstanceCreateInfo::default();
661
662 if let Some(callback) = callback {
663 callback(super::CreateInstanceCallbackArgs {
664 extensions: &mut extensions,
665 create_info: &mut create_info,
666 entry: &entry,
667 _phantom: PhantomData,
668 });
669 }
670
671 let instance_layers = {
672 profiling::scope!("vkEnumerateInstanceLayerProperties");
673 unsafe { entry.enumerate_instance_layer_properties() }
674 };
675 let instance_layers = instance_layers.map_err(|e| {
676 log::debug!("enumerate_instance_layer_properties: {e:?}");
677 crate::InstanceError::with_source(
678 String::from("enumerate_instance_layer_properties() failed"),
679 e,
680 )
681 })?;
682
683 fn find_layer<'layers>(
684 instance_layers: &'layers [vk::LayerProperties],
685 name: &CStr,
686 ) -> Option<&'layers vk::LayerProperties> {
687 instance_layers
688 .iter()
689 .find(|inst_layer| inst_layer.layer_name_as_c_str() == Ok(name))
690 }
691
692 let validation_layer_name = c"VK_LAYER_KHRONOS_validation";
693 let validation_layer_properties = find_layer(&instance_layers, validation_layer_name);
694
695 let validation_features_are_enabled = if validation_layer_properties.is_some() {
698 let exts =
700 Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?;
701 let mut ext_names = exts
703 .iter()
704 .filter_map(|ext| ext.extension_name_as_c_str().ok());
705 ext_names.any(|ext_name| ext_name == ext::validation_features::NAME)
707 } else {
708 false
709 };
710
711 let should_enable_gpu_based_validation = desc
712 .flags
713 .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
714 && validation_features_are_enabled;
715
716 let has_nv_optimus = find_layer(&instance_layers, c"VK_LAYER_NV_optimus").is_some();
717
718 let has_obs_layer = find_layer(&instance_layers, c"VK_LAYER_OBS_HOOK").is_some();
719
720 let mut layers: Vec<&'static CStr> = Vec::new();
721
722 let has_debug_extension = extensions.contains(&ext::debug_utils::NAME);
723 let mut debug_user_data = has_debug_extension.then(|| {
724 Box::new(super::DebugUtilsMessengerUserData {
727 validation_layer_properties: None,
728 has_obs_layer,
729 })
730 });
731
732 if desc.flags.intersects(wgt::InstanceFlags::VALIDATION)
734 || should_enable_gpu_based_validation
735 {
736 if let Some(layer_properties) = validation_layer_properties {
737 layers.push(validation_layer_name);
738
739 if let Some(debug_user_data) = debug_user_data.as_mut() {
740 debug_user_data.validation_layer_properties =
741 Some(super::ValidationLayerProperties {
742 layer_description: layer_properties
743 .description_as_c_str()
744 .unwrap()
745 .to_owned(),
746 layer_spec_version: layer_properties.spec_version,
747 });
748 }
749 } else {
750 log::warn!(
751 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
752 validation_layer_name.to_string_lossy()
753 );
754 }
755 }
756 let mut debug_utils = if let Some(callback_data) = debug_user_data {
757 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
759 if log::max_level() >= log::LevelFilter::Debug {
760 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
761 }
762 if log::max_level() >= log::LevelFilter::Info {
763 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
764 }
765 if log::max_level() >= log::LevelFilter::Warn {
766 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
767 }
768
769 let message_type = vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
770 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
771 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
772
773 let create_info = super::DebugUtilsCreateInfo {
774 severity,
775 message_type,
776 callback_data,
777 };
778
779 Some(create_info)
780 } else {
781 None
782 };
783
784 #[cfg(target_os = "android")]
785 let android_sdk_version = {
786 let properties = android_system_properties::AndroidSystemProperties::new();
787 if let Some(val) = properties.get("ro.build.version.sdk") {
789 match val.parse::<u32>() {
790 Ok(sdk_ver) => sdk_ver,
791 Err(err) => {
792 log::error!(
793 concat!(
794 "Couldn't parse Android's ",
795 "ro.build.version.sdk system property ({}): {}",
796 ),
797 val,
798 err,
799 );
800 0
801 }
802 }
803 } else {
804 log::error!("Couldn't read Android's ro.build.version.sdk system property");
805 0
806 }
807 };
808 #[cfg(not(target_os = "android"))]
809 let android_sdk_version = 0;
810
811 let mut flags = vk::InstanceCreateFlags::empty();
812
813 if extensions.contains(&khr::portability_enumeration::NAME) {
817 flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
818 }
819 let vk_instance = {
820 let str_pointers = layers
821 .iter()
822 .chain(extensions.iter())
823 .map(|&s: &&'static _| {
824 s.as_ptr()
826 })
827 .collect::<Vec<_>>();
828
829 create_info = create_info
830 .flags(flags)
831 .application_info(&app_info)
832 .enabled_layer_names(&str_pointers[..layers.len()])
833 .enabled_extension_names(&str_pointers[layers.len()..]);
834
835 let mut debug_utils_create_info = debug_utils
836 .as_mut()
837 .map(|create_info| create_info.to_vk_create_info());
838 if let Some(debug_utils_create_info) = debug_utils_create_info.as_mut() {
839 create_info = create_info.push_next(debug_utils_create_info);
840 }
841
842 let mut validation_features;
844 let mut validation_feature_list: ArrayVec<_, 3>;
845 if validation_features_are_enabled {
846 validation_feature_list = ArrayVec::new();
847
848 validation_feature_list
850 .push(vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION);
851
852 if should_enable_gpu_based_validation {
854 validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED);
855 validation_feature_list
856 .push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT);
857 }
858
859 validation_features = vk::ValidationFeaturesEXT::default()
860 .enabled_validation_features(&validation_feature_list);
861 create_info = create_info.push_next(&mut validation_features);
862 }
863
864 unsafe {
865 profiling::scope!("vkCreateInstance");
866 entry.create_instance(&create_info, None)
867 }
868 .map_err(|e| {
869 crate::InstanceError::with_source(
870 String::from("Entry::create_instance() failed"),
871 e,
872 )
873 })?
874 };
875
876 unsafe {
877 Self::from_raw(
878 entry,
879 vk_instance,
880 instance_api_version,
881 android_sdk_version,
882 debug_utils,
883 extensions,
884 desc.flags,
885 desc.memory_budget_thresholds,
886 has_nv_optimus,
887 None,
888 )
889 }
890 }
891}
892
893impl Drop for super::InstanceShared {
894 fn drop(&mut self) {
895 unsafe {
896 let _du = self.debug_utils.take().inspect(|du| {
898 du.extension
899 .destroy_debug_utils_messenger(du.messenger, None);
900 });
901 if self.drop_guard.is_none() {
902 self.raw.destroy_instance(None);
903 }
904 }
905 }
906}
907
908impl crate::Instance for super::Instance {
909 type A = super::Api;
910
911 unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
912 unsafe { Self::init_with_callback(desc, None) }
913 }
914
915 unsafe fn create_surface(
916 &self,
917 display_handle: raw_window_handle::RawDisplayHandle,
918 window_handle: raw_window_handle::RawWindowHandle,
919 ) -> Result<super::Surface, crate::InstanceError> {
920 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
921
922 match (window_handle, display_handle) {
925 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
926 self.create_surface_from_wayland(display.display.as_ptr(), handle.surface.as_ptr())
927 }
928 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
929 let display = display.display.expect("Display pointer is not set.");
930 self.create_surface_from_xlib(display.as_ptr(), handle.window)
931 }
932 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
933 let connection = display.connection.expect("Pointer to X-Server is not set.");
934 self.create_surface_from_xcb(connection.as_ptr(), handle.window.get())
935 }
936 (Rwh::AndroidNdk(handle), _) => {
937 self.create_surface_android(handle.a_native_window.as_ptr())
938 }
939 (Rwh::Win32(handle), _) => {
940 let hinstance = handle.hinstance.ok_or_else(|| {
941 crate::InstanceError::new(String::from(
942 "Vulkan requires raw-window-handle's Win32::hinstance to be set",
943 ))
944 })?;
945 self.create_surface_from_hwnd(hinstance.get(), handle.hwnd.get())
946 }
947 #[cfg(all(target_os = "macos", feature = "metal"))]
948 (Rwh::AppKit(handle), _)
949 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
950 {
951 self.create_surface_from_view(handle.ns_view)
952 }
953 #[cfg(all(any(target_os = "ios", target_os = "visionos"), feature = "metal"))]
954 (Rwh::UiKit(handle), _)
955 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
956 {
957 self.create_surface_from_view(handle.ui_view)
958 }
959 (_, _) => Err(crate::InstanceError::new(format!(
960 "window handle {window_handle:?} is not a Vulkan-compatible handle"
961 ))),
962 }
963 }
964
965 unsafe fn enumerate_adapters(
966 &self,
967 _surface_hint: Option<&super::Surface>,
968 ) -> Vec<crate::ExposedAdapter<super::Api>> {
969 use crate::auxil::db;
970
971 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
972 Ok(devices) => devices,
973 Err(err) => {
974 log::error!("enumerate_adapters: {err}");
975 Vec::new()
976 }
977 };
978
979 let mut exposed_adapters = raw_devices
980 .into_iter()
981 .flat_map(|device| self.expose_adapter(device))
982 .collect::<Vec<_>>();
983
984 let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| {
986 exposed.info.device_type == wgt::DeviceType::DiscreteGpu
987 && exposed.info.vendor == db::nvidia::VENDOR
988 });
989 if cfg!(target_os = "linux") && has_nvidia_dgpu && self.shared.has_nv_optimus {
990 for exposed in exposed_adapters.iter_mut() {
991 if exposed.info.device_type == wgt::DeviceType::IntegratedGpu
992 && exposed.info.vendor == db::intel::VENDOR
993 {
994 if let Some(version) = exposed.info.driver_info.split_once("Mesa ").map(|s| {
996 let mut components = s.1.split('.');
997 let major = components.next().and_then(|s| u8::from_str(s).ok());
998 let minor = components.next().and_then(|s| u8::from_str(s).ok());
999 if let (Some(major), Some(minor)) = (major, minor) {
1000 (major, minor)
1001 } else {
1002 (0, 0)
1003 }
1004 }) {
1005 if version < (21, 2) {
1006 log::warn!(
1008 concat!(
1009 "Disabling presentation on '{}' (id {:?}) ",
1010 "due to NV Optimus and Intel Mesa < v21.2"
1011 ),
1012 exposed.info.name,
1013 exposed.adapter.raw
1014 );
1015 exposed.adapter.private_caps.can_present = false;
1016 }
1017 }
1018 }
1019 }
1020 }
1021
1022 exposed_adapters
1023 }
1024}
1025
1026impl Drop for super::Surface {
1027 fn drop(&mut self) {
1028 unsafe { self.functor.destroy_surface(self.raw, None) };
1029 }
1030}
1031
1032impl crate::Surface for super::Surface {
1033 type A = super::Api;
1034
1035 unsafe fn configure(
1036 &self,
1037 device: &super::Device,
1038 config: &crate::SurfaceConfiguration,
1039 ) -> Result<(), crate::SurfaceError> {
1040 let mut swap_chain = self.swapchain.write();
1042 let old = swap_chain
1043 .take()
1044 .map(|sc| unsafe { sc.release_resources(&device.shared.raw) });
1045
1046 let swapchain = unsafe { device.create_swapchain(self, config, old)? };
1047 *swap_chain = Some(swapchain);
1048
1049 Ok(())
1050 }
1051
1052 unsafe fn unconfigure(&self, device: &super::Device) {
1053 if let Some(sc) = self.swapchain.write().take() {
1054 let swapchain = unsafe { sc.release_resources(&device.shared.raw) };
1056 unsafe { swapchain.functor.destroy_swapchain(swapchain.raw, None) };
1057 }
1058 }
1059
1060 unsafe fn acquire_texture(
1061 &self,
1062 timeout: Option<core::time::Duration>,
1063 fence: &super::Fence,
1064 ) -> Result<Option<crate::AcquiredSurfaceTexture<super::Api>>, crate::SurfaceError> {
1065 let mut swapchain = self.swapchain.write();
1066 let swapchain = swapchain.as_mut().unwrap();
1067
1068 let mut timeout_ns = match timeout {
1069 Some(duration) => duration.as_nanos() as u64,
1070 None => u64::MAX,
1071 };
1072
1073 if cfg!(target_os = "android") && self.instance.android_sdk_version < 30 {
1083 timeout_ns = u64::MAX;
1084 }
1085
1086 let acquire_semaphore_arc = swapchain.get_acquire_semaphore();
1087 let acquire_semaphore_guard = acquire_semaphore_arc
1089 .try_lock()
1090 .expect("Failed to lock a SwapchainSemaphores.");
1091
1092 swapchain.device.wait_for_fence(
1106 fence,
1107 acquire_semaphore_guard.previously_used_submission_index,
1108 timeout_ns,
1109 )?;
1110
1111 let (index, suboptimal) = match unsafe {
1113 profiling::scope!("vkAcquireNextImageKHR");
1114 swapchain.functor.acquire_next_image(
1115 swapchain.raw,
1116 timeout_ns,
1117 acquire_semaphore_guard.acquire,
1118 vk::Fence::null(),
1119 )
1120 } {
1121 #[cfg(target_os = "android")]
1124 Ok((index, _)) => (index, false),
1125 #[cfg(not(target_os = "android"))]
1126 Ok(pair) => pair,
1127 Err(error) => {
1128 return match error {
1129 vk::Result::TIMEOUT => Ok(None),
1130 vk::Result::NOT_READY | vk::Result::ERROR_OUT_OF_DATE_KHR => {
1131 Err(crate::SurfaceError::Outdated)
1132 }
1133 vk::Result::ERROR_SURFACE_LOST_KHR => Err(crate::SurfaceError::Lost),
1134 other => Err(super::map_host_device_oom_and_lost_err(other).into()),
1137 };
1138 }
1139 };
1140
1141 drop(acquire_semaphore_guard);
1142 swapchain.advance_acquire_semaphore();
1145
1146 let present_semaphore_arc = swapchain.get_present_semaphores(index);
1147
1148 if swapchain.device.vendor_id == crate::auxil::db::intel::VENDOR && index > 0x100 {
1150 return Err(crate::SurfaceError::Outdated);
1151 }
1152
1153 let identity = swapchain.device.texture_identity_factory.next();
1154
1155 let texture = super::SurfaceTexture {
1156 index,
1157 texture: super::Texture {
1158 raw: swapchain.images[index as usize],
1159 drop_guard: None,
1160 block: None,
1161 external_memory: None,
1162 format: swapchain.config.format,
1163 copy_size: crate::CopyExtent {
1164 width: swapchain.config.extent.width,
1165 height: swapchain.config.extent.height,
1166 depth: 1,
1167 },
1168 identity,
1169 },
1170 acquire_semaphores: acquire_semaphore_arc,
1171 present_semaphores: present_semaphore_arc,
1172 };
1173 Ok(Some(crate::AcquiredSurfaceTexture {
1174 texture,
1175 suboptimal,
1176 }))
1177 }
1178
1179 unsafe fn discard_texture(&self, _texture: super::SurfaceTexture) {}
1180}