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::Trace,
86 vk::DebugUtilsMessageSeverityFlagsEXT::INFO => log::Level::Debug,
87 vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => log::Level::Warn,
88 vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => log::Level::Error,
89 _ => log::Level::Warn,
90 };
91
92 let message_id_name =
93 unsafe { cd.message_id_name_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
94 let message = unsafe { cd.message_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
95
96 let _ = std::panic::catch_unwind(|| {
97 log::log!(
98 level,
99 "{:?} [{} (0x{:x})]\n\t{}",
100 message_type,
101 message_id_name,
102 cd.message_id_number,
103 message,
104 );
105 });
106
107 if cd.queue_label_count != 0 {
108 let labels =
109 unsafe { slice::from_raw_parts(cd.p_queue_labels, cd.queue_label_count as usize) };
110 let names = labels
111 .iter()
112 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
113 .collect::<Vec<_>>();
114
115 let _ = std::panic::catch_unwind(|| {
116 log::log!(level, "\tqueues: {}", names.join(", "));
117 });
118 }
119
120 if cd.cmd_buf_label_count != 0 {
121 let labels =
122 unsafe { slice::from_raw_parts(cd.p_cmd_buf_labels, cd.cmd_buf_label_count as usize) };
123 let names = labels
124 .iter()
125 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
126 .collect::<Vec<_>>();
127
128 let _ = std::panic::catch_unwind(|| {
129 log::log!(level, "\tcommand buffers: {}", names.join(", "));
130 });
131 }
132
133 if cd.object_count != 0 {
134 let labels = unsafe { slice::from_raw_parts(cd.p_objects, cd.object_count as usize) };
135 let names = labels
137 .iter()
138 .map(|obj_info| {
139 let name = unsafe { obj_info.object_name_as_c_str() }
140 .map_or(Cow::Borrowed("?"), CStr::to_string_lossy);
141
142 format!(
143 "(type: {:?}, hndl: 0x{:x}, name: {})",
144 obj_info.object_type, obj_info.object_handle, name
145 )
146 })
147 .collect::<Vec<_>>();
148 let _ = std::panic::catch_unwind(|| {
149 log::log!(level, "\tobjects: {}", names.join(", "));
150 });
151 }
152
153 #[cfg(feature = "validation_canary")]
154 if cfg!(debug_assertions) && level == log::Level::Error {
155 use alloc::string::ToString as _;
156
157 crate::VALIDATION_CANARY.add(message.to_string());
159 }
160
161 vk::FALSE
162}
163
164impl super::DebugUtilsCreateInfo {
165 fn to_vk_create_info(&self) -> vk::DebugUtilsMessengerCreateInfoEXT<'_> {
166 let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*self.callback_data;
167 vk::DebugUtilsMessengerCreateInfoEXT::default()
168 .message_severity(self.severity)
169 .message_type(self.message_type)
170 .user_data(user_data_ptr as *mut _)
171 .pfn_user_callback(Some(debug_utils_messenger_callback))
172 }
173}
174
175impl super::InstanceShared {
176 pub fn entry(&self) -> &ash::Entry {
177 &self.entry
178 }
179
180 pub fn raw_instance(&self) -> &ash::Instance {
181 &self.raw
182 }
183
184 pub fn instance_api_version(&self) -> u32 {
185 self.instance_api_version
186 }
187
188 pub fn extensions(&self) -> &[&'static CStr] {
189 &self.extensions[..]
190 }
191}
192
193impl super::Instance {
194 pub fn shared_instance(&self) -> &super::InstanceShared {
195 &self.shared
196 }
197
198 fn enumerate_instance_extension_properties(
199 entry: &ash::Entry,
200 layer_name: Option<&CStr>,
201 ) -> Result<Vec<vk::ExtensionProperties>, crate::InstanceError> {
202 let instance_extensions = {
203 profiling::scope!("vkEnumerateInstanceExtensionProperties");
204 unsafe { entry.enumerate_instance_extension_properties(layer_name) }
205 };
206 instance_extensions.map_err(|e| {
207 crate::InstanceError::with_source(
208 String::from("enumerate_instance_extension_properties() failed"),
209 e,
210 )
211 })
212 }
213
214 pub fn desired_extensions(
228 entry: &ash::Entry,
229 _instance_api_version: u32,
230 flags: wgt::InstanceFlags,
231 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
232 let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?;
233
234 let mut extensions: Vec<&'static CStr> = Vec::new();
236
237 extensions.push(khr::surface::NAME);
239
240 if cfg!(all(
242 unix,
243 not(target_os = "android"),
244 not(target_os = "macos")
245 )) {
246 extensions.push(khr::xlib_surface::NAME);
248 extensions.push(khr::xcb_surface::NAME);
250 extensions.push(khr::wayland_surface::NAME);
252 }
253 if cfg!(target_os = "android") {
254 extensions.push(khr::android_surface::NAME);
256 }
257 if cfg!(target_os = "windows") {
258 extensions.push(khr::win32_surface::NAME);
260 }
261 if cfg!(target_os = "macos") {
262 extensions.push(ext::metal_surface::NAME);
264 extensions.push(khr::portability_enumeration::NAME);
265 }
266 if cfg!(drm) {
267 extensions.push(ext::acquire_drm_display::NAME);
269 extensions.push(ext::direct_mode_display::NAME);
270 extensions.push(khr::display::NAME);
271 extensions.push(khr::get_physical_device_properties2::NAME);
272 extensions.push(khr::get_display_properties2::NAME);
273 }
274
275 if flags.contains(wgt::InstanceFlags::DEBUG) {
276 extensions.push(ext::debug_utils::NAME);
278 }
279
280 extensions.push(ext::swapchain_colorspace::NAME);
283
284 extensions.push(khr::get_physical_device_properties2::NAME);
288
289 extensions.retain(|&ext| {
291 if instance_extensions
292 .iter()
293 .any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext))
294 {
295 true
296 } else {
297 log::debug!("Unable to find extension: {}", ext.to_string_lossy());
298 false
299 }
300 });
301 Ok(extensions)
302 }
303
304 #[allow(clippy::too_many_arguments)]
317 pub unsafe fn from_raw(
318 entry: ash::Entry,
319 raw_instance: ash::Instance,
320 instance_api_version: u32,
321 android_sdk_version: u32,
322 debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
323 extensions: Vec<&'static CStr>,
324 flags: wgt::InstanceFlags,
325 memory_budget_thresholds: wgt::MemoryBudgetThresholds,
326 has_nv_optimus: bool,
327 drop_callback: Option<crate::DropCallback>,
328 ) -> Result<Self, crate::InstanceError> {
329 log::debug!("Instance version: 0x{instance_api_version:x}");
330
331 let debug_utils = if let Some(debug_utils_create_info) = debug_utils_create_info {
332 if extensions.contains(&ext::debug_utils::NAME) {
333 log::debug!("Enabling debug utils");
334
335 let extension = ext::debug_utils::Instance::new(&entry, &raw_instance);
336 let vk_info = debug_utils_create_info.to_vk_create_info();
337 let messenger =
338 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
339
340 Some(super::DebugUtils {
341 extension,
342 messenger,
343 callback_data: debug_utils_create_info.callback_data,
344 })
345 } else {
346 log::debug!("Debug utils not enabled: extension not listed");
347 None
348 }
349 } else {
350 log::debug!(
351 "Debug utils not enabled: \
352 debug_utils_user_data not passed to Instance::from_raw"
353 );
354 None
355 };
356
357 let get_physical_device_properties =
358 if extensions.contains(&khr::get_physical_device_properties2::NAME) {
359 log::debug!("Enabling device properties2");
360 Some(khr::get_physical_device_properties2::Instance::new(
361 &entry,
362 &raw_instance,
363 ))
364 } else {
365 None
366 };
367
368 let drop_guard = crate::DropGuard::from_option(drop_callback);
369
370 Ok(Self {
371 shared: Arc::new(super::InstanceShared {
372 raw: raw_instance,
373 extensions,
374 drop_guard,
375 flags,
376 memory_budget_thresholds,
377 debug_utils,
378 get_physical_device_properties,
379 entry,
380 has_nv_optimus,
381 instance_api_version,
382 android_sdk_version,
383 }),
384 })
385 }
386
387 fn create_surface_from_xlib(
388 &self,
389 dpy: *mut vk::Display,
390 window: vk::Window,
391 ) -> Result<super::Surface, crate::InstanceError> {
392 if !self.shared.extensions.contains(&khr::xlib_surface::NAME) {
393 return Err(crate::InstanceError::new(String::from(
394 "Vulkan driver does not support VK_KHR_xlib_surface",
395 )));
396 }
397
398 let surface = {
399 let xlib_loader =
400 khr::xlib_surface::Instance::new(&self.shared.entry, &self.shared.raw);
401 let info = vk::XlibSurfaceCreateInfoKHR::default()
402 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
403 .window(window)
404 .dpy(dpy);
405
406 unsafe { xlib_loader.create_xlib_surface(&info, None) }
407 .expect("XlibSurface::create_xlib_surface() failed")
408 };
409
410 Ok(self.create_surface_from_vk_surface_khr(surface, None))
411 }
412
413 fn create_surface_from_xcb(
414 &self,
415 connection: *mut vk::xcb_connection_t,
416 window: vk::xcb_window_t,
417 ) -> Result<super::Surface, crate::InstanceError> {
418 if !self.shared.extensions.contains(&khr::xcb_surface::NAME) {
419 return Err(crate::InstanceError::new(String::from(
420 "Vulkan driver does not support VK_KHR_xcb_surface",
421 )));
422 }
423
424 let surface = {
425 let xcb_loader = khr::xcb_surface::Instance::new(&self.shared.entry, &self.shared.raw);
426 let info = vk::XcbSurfaceCreateInfoKHR::default()
427 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
428 .window(window)
429 .connection(connection);
430
431 unsafe { xcb_loader.create_xcb_surface(&info, None) }
432 .expect("XcbSurface::create_xcb_surface() failed")
433 };
434
435 Ok(self.create_surface_from_vk_surface_khr(surface, None))
436 }
437
438 fn create_surface_from_wayland(
439 &self,
440 display: *mut vk::wl_display,
441 surface: *mut vk::wl_surface,
442 ) -> Result<super::Surface, crate::InstanceError> {
443 if !self.shared.extensions.contains(&khr::wayland_surface::NAME) {
444 return Err(crate::InstanceError::new(String::from(
445 "Vulkan driver does not support VK_KHR_wayland_surface",
446 )));
447 }
448
449 let surface = {
450 let w_loader =
451 khr::wayland_surface::Instance::new(&self.shared.entry, &self.shared.raw);
452 let info = vk::WaylandSurfaceCreateInfoKHR::default()
453 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
454 .display(display)
455 .surface(surface);
456
457 unsafe { w_loader.create_wayland_surface(&info, None) }.expect("WaylandSurface failed")
458 };
459
460 Ok(self.create_surface_from_vk_surface_khr(surface, None))
461 }
462
463 fn create_surface_android(
464 &self,
465 window: *mut vk::ANativeWindow,
466 ) -> Result<super::Surface, crate::InstanceError> {
467 if !self.shared.extensions.contains(&khr::android_surface::NAME) {
468 return Err(crate::InstanceError::new(String::from(
469 "Vulkan driver does not support VK_KHR_android_surface",
470 )));
471 }
472
473 let surface = {
474 let a_loader =
475 khr::android_surface::Instance::new(&self.shared.entry, &self.shared.raw);
476 let info = vk::AndroidSurfaceCreateInfoKHR::default()
477 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
478 .window(window);
479
480 unsafe { a_loader.create_android_surface(&info, None) }.expect("AndroidSurface failed")
481 };
482
483 Ok(self.create_surface_from_vk_surface_khr(surface, None))
484 }
485
486 fn create_surface_from_hwnd(
487 &self,
488 hinstance: vk::HINSTANCE,
489 hwnd: vk::HWND,
490 ) -> Result<super::Surface, crate::InstanceError> {
491 if !self.shared.extensions.contains(&khr::win32_surface::NAME) {
492 return Err(crate::InstanceError::new(String::from(
493 "Vulkan driver does not support VK_KHR_win32_surface",
494 )));
495 }
496
497 let surface = {
498 let info = vk::Win32SurfaceCreateInfoKHR::default()
499 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
500 .hinstance(hinstance)
501 .hwnd(hwnd);
502 let win32_loader =
503 khr::win32_surface::Instance::new(&self.shared.entry, &self.shared.raw);
504 unsafe {
505 win32_loader
506 .create_win32_surface(&info, None)
507 .expect("Unable to create Win32 surface")
508 }
509 };
510
511 #[cfg(windows)]
514 let window_handle = Some(crate::vulkan::swapchain::WindowHandle(
515 windows::Win32::Foundation::HWND(hwnd as *mut c_void),
516 ));
517 #[cfg(not(windows))]
518 let window_handle: Option<crate::vulkan::swapchain::WindowHandle> = None;
519 Ok(self.create_surface_from_vk_surface_khr(surface, window_handle))
520 }
521
522 #[cfg(target_vendor = "apple")]
523 fn create_surface_from_layer(
524 &self,
525 layer: raw_window_metal::Layer,
526 ) -> Result<super::Surface, crate::InstanceError> {
527 if !self.shared.extensions.contains(&ext::metal_surface::NAME) {
528 return Err(crate::InstanceError::new(String::from(
529 "Vulkan driver does not support VK_EXT_metal_surface",
530 )));
531 }
532
533 let surface = {
536 let metal_loader =
537 ext::metal_surface::Instance::new(&self.shared.entry, &self.shared.raw);
538 let vk_info = vk::MetalSurfaceCreateInfoEXT::default()
539 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
540 .layer(layer.as_ptr().as_ptr());
541
542 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
543 };
544
545 Ok(self.create_surface_from_vk_surface_khr(surface, None))
546 }
547
548 pub(super) fn create_surface_from_vk_surface_khr(
549 &self,
550 surface: vk::SurfaceKHR,
551 hwnd: Option<crate::vulkan::swapchain::WindowHandle>,
552 ) -> super::Surface {
553 let native_surface =
554 crate::vulkan::swapchain::NativeSurface::from_vk_surface_khr(self, surface, hwnd);
555
556 super::Surface {
557 swapchain: RwLock::new(None),
558 inner: Box::new(native_surface),
559 }
560 }
561
562 pub unsafe fn init_with_callback(
571 desc: &crate::InstanceDescriptor<'_>,
572 callback: Option<Box<super::CreateInstanceCallback>>,
573 ) -> Result<Self, crate::InstanceError> {
574 profiling::scope!("Init Vulkan Backend");
575
576 let entry = unsafe {
577 profiling::scope!("Load vk library");
578 #[cfg(target_env = "ohos")]
581 let loaded = ash::Entry::load_from("libvulkan.so");
582 #[cfg(not(target_env = "ohos"))]
583 let loaded = ash::Entry::load();
584 loaded
585 }
586 .map_err(|err| {
587 crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
588 })?;
589 let version = {
590 profiling::scope!("vkEnumerateInstanceVersion");
591 unsafe { entry.try_enumerate_instance_version() }
592 };
593 let instance_api_version = match version {
594 Ok(Some(version)) => version,
596 Ok(None) => vk::API_VERSION_1_0,
597 Err(err) => {
598 return Err(crate::InstanceError::with_source(
599 String::from("try_enumerate_instance_version() failed"),
600 err,
601 ));
602 }
603 };
604
605 let app_name = CString::new(desc.name).unwrap();
606 let app_info = vk::ApplicationInfo::default()
607 .application_name(app_name.as_c_str())
608 .application_version(1)
609 .engine_name(c"wgpu-hal")
610 .engine_version(2)
611 .api_version(
612 if instance_api_version < vk::API_VERSION_1_1 {
614 vk::API_VERSION_1_0
615 } else {
616 vk::API_VERSION_1_3
625 },
626 );
627
628 let mut extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
629 let mut create_info = vk::InstanceCreateInfo::default();
630
631 if let Some(callback) = callback {
632 callback(super::CreateInstanceCallbackArgs {
633 extensions: &mut extensions,
634 create_info: &mut create_info,
635 entry: &entry,
636 _phantom: PhantomData,
637 });
638 }
639
640 let instance_layers = {
641 profiling::scope!("vkEnumerateInstanceLayerProperties");
642 unsafe { entry.enumerate_instance_layer_properties() }
643 };
644 let instance_layers = instance_layers.map_err(|e| {
645 log::debug!("enumerate_instance_layer_properties: {e:?}");
646 crate::InstanceError::with_source(
647 String::from("enumerate_instance_layer_properties() failed"),
648 e,
649 )
650 })?;
651
652 fn find_layer<'layers>(
653 instance_layers: &'layers [vk::LayerProperties],
654 name: &CStr,
655 ) -> Option<&'layers vk::LayerProperties> {
656 instance_layers
657 .iter()
658 .find(|inst_layer| inst_layer.layer_name_as_c_str() == Ok(name))
659 }
660
661 let validation_layer_name = c"VK_LAYER_KHRONOS_validation";
662 let validation_layer_properties = find_layer(&instance_layers, validation_layer_name);
663
664 let validation_features_are_enabled = if validation_layer_properties.is_some() {
667 let exts =
669 Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?;
670 let mut ext_names = exts
672 .iter()
673 .filter_map(|ext| ext.extension_name_as_c_str().ok());
674 ext_names.any(|ext_name| ext_name == ext::validation_features::NAME)
676 } else {
677 false
678 };
679
680 let should_enable_gpu_based_validation = desc
681 .flags
682 .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
683 && validation_features_are_enabled;
684
685 let has_nv_optimus = find_layer(&instance_layers, c"VK_LAYER_NV_optimus").is_some();
686
687 let has_obs_layer = find_layer(&instance_layers, c"VK_LAYER_OBS_HOOK").is_some();
688
689 let mut layers: Vec<&'static CStr> = Vec::new();
690
691 let has_debug_extension = extensions.contains(&ext::debug_utils::NAME);
692 let mut debug_user_data = has_debug_extension.then(|| {
693 Box::new(super::DebugUtilsMessengerUserData {
696 validation_layer_properties: None,
697 has_obs_layer,
698 })
699 });
700
701 if desc.flags.intersects(wgt::InstanceFlags::VALIDATION)
703 || should_enable_gpu_based_validation
704 {
705 if let Some(layer_properties) = validation_layer_properties {
706 layers.push(validation_layer_name);
707
708 if let Some(debug_user_data) = debug_user_data.as_mut() {
709 debug_user_data.validation_layer_properties =
710 Some(super::ValidationLayerProperties {
711 layer_description: layer_properties
712 .description_as_c_str()
713 .unwrap()
714 .to_owned(),
715 layer_spec_version: layer_properties.spec_version,
716 });
717 }
718 } else {
719 log::debug!(
720 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
721 validation_layer_name.to_string_lossy()
722 );
723 }
724 }
725 let mut debug_utils = if let Some(callback_data) = debug_user_data {
726 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
728 if log::max_level() >= log::LevelFilter::Debug {
729 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
730 }
731 if log::max_level() >= log::LevelFilter::Info {
732 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
733 }
734 if log::max_level() >= log::LevelFilter::Warn {
735 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
736 }
737
738 let message_type = vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
739 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
740 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
741
742 let create_info = super::DebugUtilsCreateInfo {
743 severity,
744 message_type,
745 callback_data,
746 };
747
748 Some(create_info)
749 } else {
750 None
751 };
752
753 #[cfg(target_os = "android")]
754 let android_sdk_version = {
755 let properties = android_system_properties::AndroidSystemProperties::new();
756 if let Some(val) = properties.get("ro.build.version.sdk") {
758 match val.parse::<u32>() {
759 Ok(sdk_ver) => sdk_ver,
760 Err(err) => {
761 log::error!(
762 concat!(
763 "Couldn't parse Android's ",
764 "ro.build.version.sdk system property ({}): {}",
765 ),
766 val,
767 err,
768 );
769 0
770 }
771 }
772 } else {
773 log::error!("Couldn't read Android's ro.build.version.sdk system property");
774 0
775 }
776 };
777 #[cfg(not(target_os = "android"))]
778 let android_sdk_version = 0;
779
780 let mut flags = vk::InstanceCreateFlags::empty();
781
782 if extensions.contains(&khr::portability_enumeration::NAME) {
786 flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
787 }
788 let vk_instance = {
789 let str_pointers = layers
790 .iter()
791 .chain(extensions.iter())
792 .map(|&s: &&'static _| {
793 s.as_ptr()
795 })
796 .collect::<Vec<_>>();
797
798 create_info = create_info
799 .flags(flags)
800 .application_info(&app_info)
801 .enabled_layer_names(&str_pointers[..layers.len()])
802 .enabled_extension_names(&str_pointers[layers.len()..]);
803
804 let mut debug_utils_create_info = debug_utils
805 .as_mut()
806 .map(|create_info| create_info.to_vk_create_info());
807 if let Some(debug_utils_create_info) = debug_utils_create_info.as_mut() {
808 create_info = create_info.push_next(debug_utils_create_info);
809 }
810
811 let mut validation_features;
813 let mut validation_feature_list: ArrayVec<_, 3>;
814 if validation_features_are_enabled {
815 validation_feature_list = ArrayVec::new();
816
817 validation_feature_list
819 .push(vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION);
820
821 if should_enable_gpu_based_validation {
823 validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED);
824 validation_feature_list
825 .push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT);
826 }
827
828 validation_features = vk::ValidationFeaturesEXT::default()
829 .enabled_validation_features(&validation_feature_list);
830 create_info = create_info.push_next(&mut validation_features);
831 }
832
833 unsafe {
834 profiling::scope!("vkCreateInstance");
835 entry.create_instance(&create_info, None)
836 }
837 .map_err(|e| {
838 crate::InstanceError::with_source(
839 String::from("Entry::create_instance() failed"),
840 e,
841 )
842 })?
843 };
844
845 unsafe {
846 Self::from_raw(
847 entry,
848 vk_instance,
849 instance_api_version,
850 android_sdk_version,
851 debug_utils,
852 extensions,
853 desc.flags,
854 desc.memory_budget_thresholds,
855 has_nv_optimus,
856 None,
857 )
858 }
859 }
860}
861
862impl Drop for super::InstanceShared {
863 fn drop(&mut self) {
864 unsafe {
865 let _du = self.debug_utils.take().inspect(|du| {
867 du.extension
868 .destroy_debug_utils_messenger(du.messenger, None);
869 });
870 if self.drop_guard.is_none() {
871 self.raw.destroy_instance(None);
872 }
873 }
874 }
875}
876
877impl crate::Instance for super::Instance {
878 type A = super::Api;
879
880 unsafe fn init(desc: &crate::InstanceDescriptor<'_>) -> Result<Self, crate::InstanceError> {
881 unsafe { Self::init_with_callback(desc, None) }
882 }
883
884 unsafe fn create_surface(
885 &self,
886 display_handle: raw_window_handle::RawDisplayHandle,
887 window_handle: raw_window_handle::RawWindowHandle,
888 ) -> Result<super::Surface, crate::InstanceError> {
889 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
890
891 match (window_handle, display_handle) {
894 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
895 self.create_surface_from_wayland(display.display.as_ptr(), handle.surface.as_ptr())
896 }
897 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
898 let display = display.display.expect("Display pointer is not set.");
899 self.create_surface_from_xlib(display.as_ptr(), handle.window)
900 }
901 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
902 let connection = display.connection.expect("Pointer to X-Server is not set.");
903 self.create_surface_from_xcb(connection.as_ptr(), handle.window.get())
904 }
905 #[cfg(drm)]
906 (Rwh::Drm(handle), Rdh::Drm(display)) => {
907 self.create_surface_from_drm_plane(display.fd, handle.plane)
908 }
909 (Rwh::AndroidNdk(handle), _) => {
910 self.create_surface_android(handle.a_native_window.as_ptr())
911 }
912 (Rwh::Win32(handle), _) => {
913 let hinstance = handle.hinstance.ok_or_else(|| {
914 crate::InstanceError::new(String::from(
915 "Vulkan requires raw-window-handle's Win32::hinstance to be set",
916 ))
917 })?;
918 self.create_surface_from_hwnd(hinstance.get(), handle.hwnd.get())
919 }
920 #[cfg(target_vendor = "apple")]
921 (Rwh::AppKit(handle), _)
922 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
923 {
924 let layer = unsafe { raw_window_metal::Layer::from_ns_view(handle.ns_view) };
925 self.create_surface_from_layer(layer)
926 }
927 #[cfg(target_vendor = "apple")]
928 (Rwh::UiKit(handle), _)
929 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
930 {
931 let layer = unsafe { raw_window_metal::Layer::from_ui_view(handle.ui_view) };
932 self.create_surface_from_layer(layer)
933 }
934 (_, _) => Err(crate::InstanceError::new(format!(
935 "window handle {window_handle:?} is not a Vulkan-compatible handle"
936 ))),
937 }
938 }
939
940 unsafe fn enumerate_adapters(
941 &self,
942 _surface_hint: Option<&super::Surface>,
943 ) -> Vec<crate::ExposedAdapter<super::Api>> {
944 use crate::auxil::db;
945
946 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
947 Ok(devices) => devices,
948 Err(err) => {
949 log::error!("enumerate_adapters: {err}");
950 Vec::new()
951 }
952 };
953
954 let mut exposed_adapters = raw_devices
955 .into_iter()
956 .flat_map(|device| self.expose_adapter(device))
957 .collect::<Vec<_>>();
958
959 let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| {
961 exposed.info.device_type == wgt::DeviceType::DiscreteGpu
962 && exposed.info.vendor == db::nvidia::VENDOR
963 });
964 if cfg!(target_os = "linux") && has_nvidia_dgpu && self.shared.has_nv_optimus {
965 for exposed in exposed_adapters.iter_mut() {
966 if exposed.info.device_type == wgt::DeviceType::IntegratedGpu
967 && exposed.info.vendor == db::intel::VENDOR
968 {
969 if let Some(version) = exposed.info.driver_info.split_once("Mesa ").map(|s| {
971 let mut components = s.1.split('.');
972 let major = components.next().and_then(|s| u8::from_str(s).ok());
973 let minor = components.next().and_then(|s| u8::from_str(s).ok());
974 if let (Some(major), Some(minor)) = (major, minor) {
975 (major, minor)
976 } else {
977 (0, 0)
978 }
979 }) {
980 if version < (21, 2) {
981 log::debug!(
983 concat!(
984 "Disabling presentation on '{}' (id {:?}) ",
985 "due to NV Optimus and Intel Mesa < v21.2"
986 ),
987 exposed.info.name,
988 exposed.adapter.raw
989 );
990 exposed.adapter.private_caps.can_present = false;
991 }
992 }
993 }
994 }
995 }
996
997 exposed_adapters
998 }
999}
1000
1001impl crate::Surface for super::Surface {
1002 type A = super::Api;
1003
1004 unsafe fn configure(
1005 &self,
1006 device: &super::Device,
1007 config: &crate::SurfaceConfiguration,
1008 ) -> Result<(), crate::SurfaceError> {
1009 let mut swap_chain = self.swapchain.write();
1011
1012 let mut old = swap_chain.take();
1013 if let Some(ref mut old) = old {
1014 unsafe { old.release_resources(device) };
1015 }
1016
1017 let swapchain = unsafe { self.inner.create_swapchain(device, config, old)? };
1018 *swap_chain = Some(swapchain);
1019
1020 Ok(())
1021 }
1022
1023 unsafe fn unconfigure(&self, device: &super::Device) {
1024 if let Some(mut sc) = self.swapchain.write().take() {
1025 unsafe { sc.release_resources(device) };
1027 }
1028 }
1029
1030 unsafe fn acquire_texture(
1031 &self,
1032 timeout: Option<core::time::Duration>,
1033 fence: &super::Fence,
1034 ) -> Result<crate::AcquiredSurfaceTexture<super::Api>, crate::SurfaceError> {
1035 let mut swapchain = self.swapchain.write();
1036 let swapchain = swapchain.as_mut().unwrap();
1037
1038 unsafe { swapchain.acquire(timeout, fence) }
1039 }
1040
1041 unsafe fn discard_texture(&self, texture: super::SurfaceTexture) {
1042 unsafe {
1043 self.swapchain
1044 .write()
1045 .as_mut()
1046 .unwrap()
1047 .discard_texture(texture)
1048 .unwrap()
1049 };
1050 }
1051}