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