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