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
14#[cfg(target_env = "ohos")]
16const OHOS_SURFACE_EXTENSION_NAME: &CStr = c"VK_OHOS_surface";
17
18unsafe extern "system" fn debug_utils_messenger_callback(
19 message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
20 message_type: vk::DebugUtilsMessageTypeFlagsEXT,
21 callback_data_ptr: *const vk::DebugUtilsMessengerCallbackDataEXT,
22 user_data: *mut c_void,
23) -> vk::Bool32 {
24 use alloc::borrow::Cow;
25
26 if thread::panicking() {
27 return vk::FALSE;
28 }
29
30 let cd = unsafe { &*callback_data_ptr };
31 let user_data = unsafe { &*user_data.cast::<super::DebugUtilsMessengerUserData>() };
32
33 const VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912: i32 = 0x56146426;
34 if cd.message_id_number == VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912 {
35 if let Some(layer_properties) = user_data.validation_layer_properties.as_ref() {
39 if layer_properties.layer_description.as_ref() == c"Khronos Validation Layer"
40 && layer_properties.layer_spec_version >= vk::make_api_version(0, 1, 3, 240)
41 && layer_properties.layer_spec_version <= vk::make_api_version(0, 1, 3, 250)
42 {
43 return vk::FALSE;
44 }
45 }
46 }
47
48 const VUID_VKSWAPCHAINCREATEINFOKHR_PNEXT_07781: i32 = 0x4c8929c1;
52 if cd.message_id_number == VUID_VKSWAPCHAINCREATEINFOKHR_PNEXT_07781 {
53 return vk::FALSE;
54 }
55
56 const VUID_VKRENDERPASSBEGININFO_FRAMEBUFFER_04627: i32 = 0x45125641;
63 if cd.message_id_number == VUID_VKRENDERPASSBEGININFO_FRAMEBUFFER_04627
64 && user_data.has_obs_layer
65 {
66 return vk::FALSE;
67 }
68
69 const VUID_VKCMDCOPYIMAGETOBUFFER_PREGIONS_00184: i32 = 0x45ef177c;
73 if cd.message_id_number == VUID_VKCMDCOPYIMAGETOBUFFER_PREGIONS_00184 {
74 return vk::FALSE;
75 }
76
77 const VUID_STANDALONESPIRV_NONE_10684: i32 = 0xb210f7c2_u32 as i32;
82 if cd.message_id_number == VUID_STANDALONESPIRV_NONE_10684 {
83 return vk::FALSE;
84 }
85
86 let level = match message_severity {
87 vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => log::Level::Trace,
90 vk::DebugUtilsMessageSeverityFlagsEXT::INFO => log::Level::Debug,
91 vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => log::Level::Warn,
92 vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => log::Level::Error,
93 _ => log::Level::Warn,
94 };
95
96 let message_id_name =
97 unsafe { cd.message_id_name_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
98 let message = unsafe { cd.message_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
99
100 let _ = std::panic::catch_unwind(|| {
101 log::log!(
102 level,
103 "{:?} [{} (0x{:x})]\n\t{}",
104 message_type,
105 message_id_name,
106 cd.message_id_number,
107 message,
108 );
109 });
110
111 if cd.queue_label_count != 0 {
112 let labels =
113 unsafe { slice::from_raw_parts(cd.p_queue_labels, cd.queue_label_count as usize) };
114 let names = labels
115 .iter()
116 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
117 .collect::<Vec<_>>();
118
119 let _ = std::panic::catch_unwind(|| {
120 log::log!(level, "\tqueues: {}", names.join(", "));
121 });
122 }
123
124 if cd.cmd_buf_label_count != 0 {
125 let labels =
126 unsafe { slice::from_raw_parts(cd.p_cmd_buf_labels, cd.cmd_buf_label_count as usize) };
127 let names = labels
128 .iter()
129 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
130 .collect::<Vec<_>>();
131
132 let _ = std::panic::catch_unwind(|| {
133 log::log!(level, "\tcommand buffers: {}", names.join(", "));
134 });
135 }
136
137 if cd.object_count != 0 {
138 let labels = unsafe { slice::from_raw_parts(cd.p_objects, cd.object_count as usize) };
139 let names = labels
141 .iter()
142 .map(|obj_info| {
143 let name = unsafe { obj_info.object_name_as_c_str() }
144 .map_or(Cow::Borrowed("?"), CStr::to_string_lossy);
145
146 format!(
147 "(type: {:?}, hndl: 0x{:x}, name: {})",
148 obj_info.object_type, obj_info.object_handle, name
149 )
150 })
151 .collect::<Vec<_>>();
152 let _ = std::panic::catch_unwind(|| {
153 log::log!(level, "\tobjects: {}", names.join(", "));
154 });
155 }
156
157 #[cfg(feature = "validation_canary")]
158 if cfg!(debug_assertions) && level == log::Level::Error {
159 use alloc::string::ToString as _;
160
161 crate::VALIDATION_CANARY.add(message.to_string());
163 }
164
165 #[cfg(all(debug_assertions, feature = "internal_error_panic"))]
166 if level == log::Level::Error
167 && message_type.contains(vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION)
168 && !error_is_waived(cd.message_id_number)
169 && !cts_error_is_waived(cd.message_id_number)
170 {
171 use alloc::string::ToString as _;
172 panic!("{}", message.to_string());
173 }
174
175 vk::FALSE
176}
177
178#[cfg(feature = "internal_error_panic")]
182fn error_is_waived(message_id_number: i32) -> bool {
183 const WAIVED_MESSAGE_IDS: &[i32] = &[
184 0x5c0ec5d6_u32 as i32,
189 ];
190
191 WAIVED_MESSAGE_IDS.contains(&message_id_number)
192}
193
194#[cfg(feature = "internal_error_panic")]
199fn cts_error_is_waived(message_id_number: i32) -> bool {
200 use std::sync::LazyLock;
201
202 static WGPU_CTS_XTASK: LazyLock<bool> =
203 LazyLock::new(|| std::env::var_os("WGPU_CTS_XTASK").is_some());
204
205 if !*WGPU_CTS_XTASK {
206 return false;
207 }
208
209 const WAIVED_MESSAGE_IDS: &[i32] = &[
210 0x34d444b2_u32 as i32,
213 0x6b654496_u32 as i32,
216 0x82396078_u32 as i32,
219 0xa3614f8b_u32 as i32,
222 0xa4164ba5_u32 as i32,
225 0xb75da543_u32 as i32,
228 0xf6d454db_u32 as i32,
231 ];
232
233 WAIVED_MESSAGE_IDS.contains(&message_id_number)
234}
235
236impl super::DebugUtilsCreateInfo {
237 fn to_vk_create_info(&self) -> vk::DebugUtilsMessengerCreateInfoEXT<'_> {
238 let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*self.callback_data;
239 vk::DebugUtilsMessengerCreateInfoEXT::default()
240 .message_severity(self.severity)
241 .message_type(self.message_type)
242 .user_data(user_data_ptr as *mut _)
243 .pfn_user_callback(Some(debug_utils_messenger_callback))
244 }
245}
246
247impl super::InstanceShared {
248 pub fn entry(&self) -> &ash::Entry {
249 &self.entry
250 }
251
252 pub fn raw_instance(&self) -> &ash::Instance {
253 &self.raw
254 }
255
256 pub fn instance_api_version(&self) -> u32 {
257 self.instance_api_version
258 }
259
260 pub fn extensions(&self) -> &[&'static CStr] {
261 &self.extensions[..]
262 }
263}
264
265impl super::Instance {
266 pub fn shared_instance(&self) -> &super::InstanceShared {
267 &self.shared
268 }
269
270 fn enumerate_instance_extension_properties(
271 entry: &ash::Entry,
272 layer_name: Option<&CStr>,
273 ) -> Result<Vec<vk::ExtensionProperties>, crate::InstanceError> {
274 let instance_extensions = {
275 profiling::scope!("vkEnumerateInstanceExtensionProperties");
276 unsafe { entry.enumerate_instance_extension_properties(layer_name) }
277 };
278 instance_extensions.map_err(|e| {
279 crate::InstanceError::with_source(
280 String::from("enumerate_instance_extension_properties() failed"),
281 e,
282 )
283 })
284 }
285
286 pub fn desired_extensions(
300 entry: &ash::Entry,
301 _instance_api_version: u32,
302 flags: wgt::InstanceFlags,
303 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
304 let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?;
305
306 let mut extensions: Vec<&'static CStr> = Vec::new();
308
309 extensions.push(khr::surface::NAME);
311
312 if cfg!(all(
314 unix,
315 not(target_os = "android"),
316 not(target_os = "macos"),
317 not(target_env = "ohos")
320 )) {
321 extensions.push(khr::xlib_surface::NAME);
323 extensions.push(khr::xcb_surface::NAME);
325 extensions.push(khr::wayland_surface::NAME);
327 }
328 if cfg!(target_os = "android") {
329 extensions.push(khr::android_surface::NAME);
331 }
332 #[cfg(target_env = "ohos")]
333 {
334 extensions.push(OHOS_SURFACE_EXTENSION_NAME);
336 }
337 if cfg!(target_os = "windows") {
338 extensions.push(khr::win32_surface::NAME);
340 }
341 if cfg!(target_os = "macos") {
342 extensions.push(ext::metal_surface::NAME);
344 extensions.push(khr::portability_enumeration::NAME);
345 }
346 if cfg!(drm) {
347 extensions.push(ext::acquire_drm_display::NAME);
349 extensions.push(ext::direct_mode_display::NAME);
350 extensions.push(khr::display::NAME);
351 extensions.push(khr::get_physical_device_properties2::NAME);
352 extensions.push(khr::get_display_properties2::NAME);
353 }
354
355 if flags.contains(wgt::InstanceFlags::DEBUG) {
356 extensions.push(ext::debug_utils::NAME);
358 }
359
360 extensions.push(ext::swapchain_colorspace::NAME);
363
364 extensions.push(khr::get_physical_device_properties2::NAME);
368
369 extensions.retain(|&ext| {
371 if instance_extensions
372 .iter()
373 .any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext))
374 {
375 true
376 } else {
377 log::debug!("Unable to find extension: {}", ext.to_string_lossy());
378 false
379 }
380 });
381 Ok(extensions)
382 }
383
384 #[allow(clippy::too_many_arguments)]
397 pub unsafe fn from_raw(
398 entry: ash::Entry,
399 raw_instance: ash::Instance,
400 instance_api_version: u32,
401 android_sdk_version: u32,
402 debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
403 extensions: Vec<&'static CStr>,
404 flags: wgt::InstanceFlags,
405 memory_budget_thresholds: wgt::MemoryBudgetThresholds,
406 has_nv_optimus: bool,
407 drop_callback: Option<crate::DropCallback>,
408 ) -> Result<Self, crate::InstanceError> {
409 log::debug!("Instance version: 0x{instance_api_version:x}");
410
411 let debug_utils = if let Some(debug_utils_create_info) = debug_utils_create_info {
412 if extensions.contains(&ext::debug_utils::NAME) {
413 log::debug!("Enabling debug utils");
414
415 let extension = ext::debug_utils::Instance::new(&entry, &raw_instance);
416 let vk_info = debug_utils_create_info.to_vk_create_info();
417 let messenger =
418 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
419
420 Some(super::DebugUtils {
421 extension,
422 messenger,
423 callback_data: debug_utils_create_info.callback_data,
424 })
425 } else {
426 log::debug!("Debug utils not enabled: extension not listed");
427 None
428 }
429 } else {
430 log::debug!(
431 "Debug utils not enabled: \
432 debug_utils_user_data not passed to Instance::from_raw"
433 );
434 None
435 };
436
437 let get_physical_device_properties =
438 if extensions.contains(&khr::get_physical_device_properties2::NAME) {
439 log::debug!("Enabling device properties2");
440 Some(khr::get_physical_device_properties2::Instance::new(
441 &entry,
442 &raw_instance,
443 ))
444 } else {
445 None
446 };
447
448 let drop_guard = crate::DropGuard::from_option(drop_callback);
449
450 Ok(Self {
451 shared: Arc::new(super::InstanceShared {
452 raw: raw_instance,
453 extensions,
454 drop_guard,
455 flags,
456 memory_budget_thresholds,
457 debug_utils,
458 get_physical_device_properties,
459 entry,
460 has_nv_optimus,
461 instance_api_version,
462 android_sdk_version,
463 }),
464 })
465 }
466
467 fn create_surface_from_xlib(
468 &self,
469 dpy: *mut vk::Display,
470 window: vk::Window,
471 ) -> Result<super::Surface, crate::InstanceError> {
472 if !self.shared.extensions.contains(&khr::xlib_surface::NAME) {
473 return Err(crate::InstanceError::new(String::from(
474 "Vulkan driver does not support VK_KHR_xlib_surface",
475 )));
476 }
477
478 let surface = {
479 let xlib_loader =
480 khr::xlib_surface::Instance::new(&self.shared.entry, &self.shared.raw);
481 let info = vk::XlibSurfaceCreateInfoKHR::default()
482 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
483 .window(window)
484 .dpy(dpy);
485
486 unsafe { xlib_loader.create_xlib_surface(&info, None) }
487 }
488 .map_err(|err| {
489 crate::InstanceError::with_source(
490 String::from("XlibSurface::create_xlib_surface() failed"),
491 err,
492 )
493 })?;
494
495 Ok(self.create_surface_from_vk_surface_khr(surface, None))
496 }
497
498 fn create_surface_from_xcb(
499 &self,
500 connection: *mut vk::xcb_connection_t,
501 window: vk::xcb_window_t,
502 ) -> Result<super::Surface, crate::InstanceError> {
503 if !self.shared.extensions.contains(&khr::xcb_surface::NAME) {
504 return Err(crate::InstanceError::new(String::from(
505 "Vulkan driver does not support VK_KHR_xcb_surface",
506 )));
507 }
508
509 let surface = {
510 let xcb_loader = khr::xcb_surface::Instance::new(&self.shared.entry, &self.shared.raw);
511 let info = vk::XcbSurfaceCreateInfoKHR::default()
512 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
513 .window(window)
514 .connection(connection);
515
516 unsafe { xcb_loader.create_xcb_surface(&info, None) }
517 }
518 .map_err(|err| {
519 crate::InstanceError::with_source(
520 String::from("XcbSurface::create_xcb_surface() failed"),
521 err,
522 )
523 })?;
524
525 Ok(self.create_surface_from_vk_surface_khr(surface, None))
526 }
527
528 fn create_surface_from_wayland(
529 &self,
530 display: *mut vk::wl_display,
531 surface: *mut vk::wl_surface,
532 ) -> Result<super::Surface, crate::InstanceError> {
533 if !self.shared.extensions.contains(&khr::wayland_surface::NAME) {
534 return Err(crate::InstanceError::new(String::from(
535 "Vulkan driver does not support VK_KHR_wayland_surface",
536 )));
537 }
538
539 let surface = {
540 let w_loader =
541 khr::wayland_surface::Instance::new(&self.shared.entry, &self.shared.raw);
542 let info = vk::WaylandSurfaceCreateInfoKHR::default()
543 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
544 .display(display)
545 .surface(surface);
546
547 unsafe { w_loader.create_wayland_surface(&info, None) }
548 }
549 .map_err(|err| {
550 crate::InstanceError::with_source(String::from("WaylandSurface failed"), err)
551 })?;
552
553 Ok(self.create_surface_from_vk_surface_khr(surface, None))
554 }
555
556 fn create_surface_android(
557 &self,
558 window: *mut vk::ANativeWindow,
559 ) -> Result<super::Surface, crate::InstanceError> {
560 if !self.shared.extensions.contains(&khr::android_surface::NAME) {
561 return Err(crate::InstanceError::new(String::from(
562 "Vulkan driver does not support VK_KHR_android_surface",
563 )));
564 }
565
566 let surface = {
567 let a_loader =
568 khr::android_surface::Instance::new(&self.shared.entry, &self.shared.raw);
569 let info = vk::AndroidSurfaceCreateInfoKHR::default()
570 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
571 .window(window);
572
573 unsafe { a_loader.create_android_surface(&info, None) }
574 }
575 .map_err(|err| {
576 crate::InstanceError::with_source(String::from("AndroidSurface failed"), err)
577 })?;
578
579 Ok(self.create_surface_from_vk_surface_khr(surface, None))
580 }
581
582 #[cfg(target_env = "ohos")]
591 fn create_surface_ohos(
592 &self,
593 window: *mut c_void,
594 ) -> Result<super::Surface, crate::InstanceError> {
595 #[repr(C)]
598 struct VkSurfaceCreateInfoOHOS {
599 s_type: vk::StructureType,
600 p_next: *const c_void,
601 flags: vk::Flags,
602 window: *mut c_void,
603 }
604
605 const S_TYPE_SURFACE_CREATE_INFO_OHOS: vk::StructureType =
608 vk::StructureType::from_raw(1000685000);
609
610 type PfnCreateSurfaceOHOS = unsafe extern "system" fn(
613 vk::Instance,
614 *const VkSurfaceCreateInfoOHOS,
615 *const vk::AllocationCallbacks,
616 *mut vk::SurfaceKHR,
617 ) -> vk::Result;
618
619 if !self
620 .shared
621 .extensions
622 .contains(&OHOS_SURFACE_EXTENSION_NAME)
623 {
624 return Err(crate::InstanceError::new(String::from(
625 "Vulkan driver does not support VK_OHOS_surface",
626 )));
627 }
628
629 let raw_instance = self.shared.raw.handle();
630
631 let create = unsafe {
636 self.shared
637 .entry
638 .get_instance_proc_addr(raw_instance, c"vkCreateSurfaceOHOS".as_ptr())
639 };
640 let create =
641 unsafe { core::mem::transmute::<vk::PFN_vkVoidFunction, Option<PfnCreateSurfaceOHOS>>(create) };
644 let Some(create) = create else {
645 return Err(crate::InstanceError::new(String::from(
646 "vkCreateSurfaceOHOS not exposed by Vulkan driver",
647 )));
648 };
649
650 let info = VkSurfaceCreateInfoOHOS {
651 s_type: S_TYPE_SURFACE_CREATE_INFO_OHOS,
652 p_next: core::ptr::null(),
653 flags: 0,
654 window,
655 };
656 let mut surface = vk::SurfaceKHR::null();
657 let result = unsafe { create(raw_instance, &info, core::ptr::null(), &mut surface) };
663 if result != vk::Result::SUCCESS {
664 return Err(crate::InstanceError::new(format!(
665 "vkCreateSurfaceOHOS failed: {result:?}"
666 )));
667 }
668
669 Ok(self.create_surface_from_vk_surface_khr(surface, None))
670 }
671
672 fn create_surface_from_hwnd(
673 &self,
674 hinstance: vk::HINSTANCE,
675 hwnd: vk::HWND,
676 ) -> Result<super::Surface, crate::InstanceError> {
677 if !self.shared.extensions.contains(&khr::win32_surface::NAME) {
678 return Err(crate::InstanceError::new(String::from(
679 "Vulkan driver does not support VK_KHR_win32_surface",
680 )));
681 }
682
683 let surface = {
684 let info = vk::Win32SurfaceCreateInfoKHR::default()
685 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
686 .hinstance(hinstance)
687 .hwnd(hwnd);
688 let win32_loader =
689 khr::win32_surface::Instance::new(&self.shared.entry, &self.shared.raw);
690 unsafe { win32_loader.create_win32_surface(&info, None) }
691 }
692 .map_err(|err| {
693 crate::InstanceError::with_source(String::from("Unable to create Win32 surface"), err)
694 })?;
695
696 #[cfg(windows)]
699 let window_handle = Some(crate::vulkan::swapchain::WindowHandle(
700 windows::Win32::Foundation::HWND(hwnd as *mut c_void),
701 ));
702 #[cfg(not(windows))]
703 let window_handle: Option<crate::vulkan::swapchain::WindowHandle> = None;
704 Ok(self.create_surface_from_vk_surface_khr(surface, window_handle))
705 }
706
707 #[cfg(target_vendor = "apple")]
708 fn create_surface_from_layer(
709 &self,
710 layer: raw_window_metal::Layer,
711 ) -> Result<super::Surface, crate::InstanceError> {
712 if !self.shared.extensions.contains(&ext::metal_surface::NAME) {
713 return Err(crate::InstanceError::new(String::from(
714 "Vulkan driver does not support VK_EXT_metal_surface",
715 )));
716 }
717
718 let surface = {
721 let metal_loader =
722 ext::metal_surface::Instance::new(&self.shared.entry, &self.shared.raw);
723 let vk_info = vk::MetalSurfaceCreateInfoEXT::default()
724 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
725 .layer(layer.as_ptr().as_ptr());
726
727 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
728 };
729
730 Ok(self.create_surface_from_vk_surface_khr(surface, None))
731 }
732
733 pub(super) fn create_surface_from_vk_surface_khr(
734 &self,
735 surface: vk::SurfaceKHR,
736 hwnd: Option<crate::vulkan::swapchain::WindowHandle>,
737 ) -> super::Surface {
738 let native_surface =
739 crate::vulkan::swapchain::NativeSurface::from_vk_surface_khr(self, surface, hwnd);
740
741 super::Surface {
742 swapchain: RwLock::new(None),
743 inner: Box::new(native_surface),
744 }
745 }
746
747 pub unsafe fn init_with_callback(
756 desc: &crate::InstanceDescriptor<'_>,
757 callback: Option<Box<super::CreateInstanceCallback>>,
758 ) -> Result<Self, crate::InstanceError> {
759 profiling::scope!("Init Vulkan Backend");
760
761 let entry = unsafe {
762 profiling::scope!("Load vk library");
763 #[cfg(target_env = "ohos")]
766 let loaded = ash::Entry::load_from("libvulkan.so");
767 #[cfg(not(target_env = "ohos"))]
768 let loaded = ash::Entry::load();
769 loaded
770 }
771 .map_err(|err| {
772 crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
773 })?;
774 let version = {
775 profiling::scope!("vkEnumerateInstanceVersion");
776 unsafe { entry.try_enumerate_instance_version() }
777 };
778 let instance_api_version = match version {
779 Ok(Some(version)) => version,
781 Ok(None) => vk::API_VERSION_1_0,
782 Err(err) => {
783 return Err(crate::InstanceError::with_source(
784 String::from("try_enumerate_instance_version() failed"),
785 err,
786 ));
787 }
788 };
789
790 let app_name = CString::new(desc.name).unwrap();
791 let app_info = vk::ApplicationInfo::default()
792 .application_name(app_name.as_c_str())
793 .application_version(1)
794 .engine_name(c"wgpu-hal")
795 .engine_version(2)
796 .api_version(
797 if instance_api_version < vk::API_VERSION_1_1 {
799 vk::API_VERSION_1_0
800 } else {
801 vk::API_VERSION_1_3
810 },
811 );
812
813 let mut extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
814 let mut create_info = vk::InstanceCreateInfo::default();
815
816 if let Some(callback) = callback {
817 callback(super::CreateInstanceCallbackArgs {
818 extensions: &mut extensions,
819 create_info: &mut create_info,
820 entry: &entry,
821 _phantom: PhantomData,
822 });
823 }
824
825 let instance_layers = {
826 profiling::scope!("vkEnumerateInstanceLayerProperties");
827 unsafe { entry.enumerate_instance_layer_properties() }
828 };
829 let instance_layers = instance_layers.map_err(|e| {
830 log::debug!("enumerate_instance_layer_properties: {e:?}");
831 crate::InstanceError::with_source(
832 String::from("enumerate_instance_layer_properties() failed"),
833 e,
834 )
835 })?;
836
837 fn find_layer<'layers>(
838 instance_layers: &'layers [vk::LayerProperties],
839 name: &CStr,
840 ) -> Option<&'layers vk::LayerProperties> {
841 instance_layers
842 .iter()
843 .find(|inst_layer| inst_layer.layer_name_as_c_str() == Ok(name))
844 }
845
846 let validation_layer_name = c"VK_LAYER_KHRONOS_validation";
847 let validation_layer_properties = find_layer(&instance_layers, validation_layer_name);
848
849 let validation_features_are_enabled = if validation_layer_properties.is_some() {
852 let exts =
854 Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?;
855 let mut ext_names = exts
857 .iter()
858 .filter_map(|ext| ext.extension_name_as_c_str().ok());
859 ext_names.any(|ext_name| ext_name == ext::validation_features::NAME)
861 } else {
862 false
863 };
864
865 let should_enable_gpu_based_validation = desc
866 .flags
867 .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
868 && validation_features_are_enabled;
869
870 let has_nv_optimus = find_layer(&instance_layers, c"VK_LAYER_NV_optimus").is_some();
871
872 let has_obs_layer = find_layer(&instance_layers, c"VK_LAYER_OBS_HOOK").is_some();
873
874 let mut layers: Vec<&'static CStr> = Vec::new();
875
876 let has_debug_extension = extensions.contains(&ext::debug_utils::NAME);
877 let mut debug_user_data = has_debug_extension.then(|| {
878 Box::new(super::DebugUtilsMessengerUserData {
881 validation_layer_properties: None,
882 has_obs_layer,
883 })
884 });
885
886 if desc.flags.intersects(wgt::InstanceFlags::VALIDATION)
888 || should_enable_gpu_based_validation
889 {
890 if let Some(layer_properties) = validation_layer_properties {
891 layers.push(validation_layer_name);
892
893 if let Some(debug_user_data) = debug_user_data.as_mut() {
894 debug_user_data.validation_layer_properties =
895 Some(super::ValidationLayerProperties {
896 layer_description: layer_properties
897 .description_as_c_str()
898 .unwrap()
899 .to_owned(),
900 layer_spec_version: layer_properties.spec_version,
901 });
902 }
903 } else {
904 log::debug!(
905 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
906 validation_layer_name.to_string_lossy()
907 );
908 }
909 }
910 let mut debug_utils = if let Some(callback_data) = debug_user_data {
911 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
913 if log::max_level() >= log::LevelFilter::Debug {
914 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
915 }
916 if log::max_level() >= log::LevelFilter::Info {
917 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
918 }
919 if log::max_level() >= log::LevelFilter::Warn {
920 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
921 }
922
923 let message_type = vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
924 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
925 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
926
927 let create_info = super::DebugUtilsCreateInfo {
928 severity,
929 message_type,
930 callback_data,
931 };
932
933 Some(create_info)
934 } else {
935 None
936 };
937
938 #[cfg(target_os = "android")]
939 let android_sdk_version = {
940 let properties = android_system_properties::AndroidSystemProperties::new();
941 if let Some(val) = properties.get("ro.build.version.sdk") {
943 match val.parse::<u32>() {
944 Ok(sdk_ver) => sdk_ver,
945 Err(err) => {
946 log::error!(
947 concat!(
948 "Couldn't parse Android's ",
949 "ro.build.version.sdk system property ({}): {}",
950 ),
951 val,
952 err,
953 );
954 0
955 }
956 }
957 } else {
958 log::error!("Couldn't read Android's ro.build.version.sdk system property");
959 0
960 }
961 };
962 #[cfg(not(target_os = "android"))]
963 let android_sdk_version = 0;
964
965 let mut flags = vk::InstanceCreateFlags::empty();
966
967 if extensions.contains(&khr::portability_enumeration::NAME) {
971 flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
972 }
973 let vk_instance = {
974 let str_pointers = layers
975 .iter()
976 .chain(extensions.iter())
977 .map(|&s: &&'static _| {
978 s.as_ptr()
980 })
981 .collect::<Vec<_>>();
982
983 create_info = create_info
984 .flags(flags)
985 .application_info(&app_info)
986 .enabled_layer_names(&str_pointers[..layers.len()])
987 .enabled_extension_names(&str_pointers[layers.len()..]);
988
989 let mut debug_utils_create_info = debug_utils
990 .as_mut()
991 .map(|create_info| create_info.to_vk_create_info());
992 if let Some(debug_utils_create_info) = debug_utils_create_info.as_mut() {
993 create_info = create_info.push_next(debug_utils_create_info);
994 }
995
996 let mut validation_features;
998 let mut validation_feature_list: ArrayVec<_, 3>;
999 if validation_features_are_enabled {
1000 validation_feature_list = ArrayVec::new();
1001
1002 validation_feature_list
1004 .push(vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION);
1005
1006 if should_enable_gpu_based_validation {
1008 validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED);
1009 validation_feature_list
1010 .push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT);
1011 }
1012
1013 validation_features = vk::ValidationFeaturesEXT::default()
1014 .enabled_validation_features(&validation_feature_list);
1015 create_info = create_info.push_next(&mut validation_features);
1016 }
1017
1018 unsafe {
1019 profiling::scope!("vkCreateInstance");
1020 entry.create_instance(&create_info, None)
1021 }
1022 .map_err(|e| {
1023 crate::InstanceError::with_source(
1024 String::from("Entry::create_instance() failed"),
1025 e,
1026 )
1027 })?
1028 };
1029
1030 unsafe {
1031 Self::from_raw(
1032 entry,
1033 vk_instance,
1034 instance_api_version,
1035 android_sdk_version,
1036 debug_utils,
1037 extensions,
1038 desc.flags,
1039 desc.memory_budget_thresholds,
1040 has_nv_optimus,
1041 None,
1042 )
1043 }
1044 }
1045}
1046
1047impl Drop for super::InstanceShared {
1048 fn drop(&mut self) {
1049 unsafe {
1050 let _du = self.debug_utils.take().inspect(|du| {
1052 du.extension
1053 .destroy_debug_utils_messenger(du.messenger, None);
1054 });
1055 if self.drop_guard.is_none() {
1056 self.raw.destroy_instance(None);
1057 }
1058 }
1059 }
1060}
1061
1062impl crate::Instance for super::Instance {
1063 type A = super::Api;
1064
1065 unsafe fn init(desc: &crate::InstanceDescriptor<'_>) -> Result<Self, crate::InstanceError> {
1066 unsafe { Self::init_with_callback(desc, None) }
1067 }
1068
1069 unsafe fn create_surface(
1070 &self,
1071 display_handle: raw_window_handle::RawDisplayHandle,
1072 window_handle: raw_window_handle::RawWindowHandle,
1073 ) -> Result<super::Surface, crate::InstanceError> {
1074 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
1075
1076 match (window_handle, display_handle) {
1079 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
1080 self.create_surface_from_wayland(display.display.as_ptr(), handle.surface.as_ptr())
1081 }
1082 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
1083 let display = display.display.expect("Display pointer is not set.");
1084 self.create_surface_from_xlib(display.as_ptr(), handle.window)
1085 }
1086 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
1087 let connection = display.connection.expect("Pointer to X-Server is not set.");
1088 self.create_surface_from_xcb(connection.as_ptr(), handle.window.get())
1089 }
1090 #[cfg(drm)]
1091 (Rwh::Drm(handle), Rdh::Drm(display)) => {
1092 self.create_surface_from_drm_plane(display.fd, handle.plane)
1093 }
1094 (Rwh::AndroidNdk(handle), _) => {
1095 self.create_surface_android(handle.a_native_window.as_ptr())
1096 }
1097 #[cfg(target_env = "ohos")]
1098 (Rwh::OhosNdk(handle), _) => self.create_surface_ohos(handle.native_window.as_ptr()),
1099 (Rwh::Win32(handle), _) => {
1100 let hinstance = handle.hinstance.ok_or_else(|| {
1101 crate::InstanceError::new(String::from(
1102 "Vulkan requires raw-window-handle's Win32::hinstance to be set",
1103 ))
1104 })?;
1105 self.create_surface_from_hwnd(hinstance.get(), handle.hwnd.get())
1106 }
1107 #[cfg(target_vendor = "apple")]
1108 (Rwh::AppKit(handle), _)
1109 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
1110 {
1111 let layer = unsafe { raw_window_metal::Layer::from_ns_view(handle.ns_view) };
1112 self.create_surface_from_layer(layer)
1113 }
1114 #[cfg(target_vendor = "apple")]
1115 (Rwh::UiKit(handle), _)
1116 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
1117 {
1118 let layer = unsafe { raw_window_metal::Layer::from_ui_view(handle.ui_view) };
1119 self.create_surface_from_layer(layer)
1120 }
1121 (_, _) => Err(crate::InstanceError::new(format!(
1122 "window handle {window_handle:?} is not a Vulkan-compatible handle"
1123 ))),
1124 }
1125 }
1126
1127 unsafe fn enumerate_adapters(
1128 &self,
1129 _surface_hint: Option<&super::Surface>,
1130 ) -> Vec<crate::ExposedAdapter<super::Api>> {
1131 use crate::auxil::db;
1132
1133 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
1134 Ok(devices) => devices,
1135 Err(err) => {
1136 log::error!("enumerate_adapters: {err}");
1137 Vec::new()
1138 }
1139 };
1140
1141 let mut exposed_adapters = raw_devices
1142 .into_iter()
1143 .flat_map(|device| self.expose_adapter(device))
1144 .collect::<Vec<_>>();
1145
1146 let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| {
1148 exposed.info.device_type == wgt::DeviceType::DiscreteGpu
1149 && exposed.info.vendor == db::nvidia::VENDOR
1150 });
1151 if cfg!(target_os = "linux") && has_nvidia_dgpu && self.shared.has_nv_optimus {
1152 for exposed in exposed_adapters.iter_mut() {
1153 if exposed.info.device_type == wgt::DeviceType::IntegratedGpu
1154 && exposed.info.vendor == db::intel::VENDOR
1155 {
1156 if let Some(version) = exposed.info.driver_info.split_once("Mesa ").map(|s| {
1158 let mut components = s.1.split('.');
1159 let major = components.next().and_then(|s| u8::from_str(s).ok());
1160 let minor = components.next().and_then(|s| u8::from_str(s).ok());
1161 if let (Some(major), Some(minor)) = (major, minor) {
1162 (major, minor)
1163 } else {
1164 (0, 0)
1165 }
1166 }) {
1167 if version < (21, 2) {
1168 log::debug!(
1170 concat!(
1171 "Disabling presentation on '{}' (id {:?}) ",
1172 "due to NV Optimus and Intel Mesa < v21.2"
1173 ),
1174 exposed.info.name,
1175 exposed.adapter.raw
1176 );
1177 exposed.adapter.private_caps.can_present = false;
1178 }
1179 }
1180 }
1181 }
1182 }
1183
1184 exposed_adapters
1185 }
1186}
1187
1188impl crate::Surface for super::Surface {
1189 type A = super::Api;
1190
1191 unsafe fn configure(
1192 &self,
1193 device: &super::Device,
1194 config: &crate::SurfaceConfiguration,
1195 ) -> Result<(), crate::SurfaceError> {
1196 let mut swap_chain = self.swapchain.write();
1198
1199 let mut old = swap_chain.take();
1200 if let Some(ref mut old) = old {
1201 unsafe { old.release_resources(device) };
1202 }
1203
1204 let swapchain = unsafe { self.inner.create_swapchain(device, config, old)? };
1205 *swap_chain = Some(swapchain);
1206
1207 Ok(())
1208 }
1209
1210 unsafe fn unconfigure(&self, device: &super::Device) {
1211 if let Some(mut sc) = self.swapchain.write().take() {
1212 unsafe { sc.release_resources(device) };
1214 }
1215 }
1216
1217 unsafe fn acquire_texture(
1218 &self,
1219 timeout: Option<core::time::Duration>,
1220 fence: &super::Fence,
1221 ) -> Result<crate::AcquiredSurfaceTexture<super::Api>, crate::SurfaceError> {
1222 let mut swapchain = self.swapchain.write();
1223 let swapchain = swapchain.as_mut().unwrap();
1224
1225 unsafe { swapchain.acquire(timeout, fence) }
1226 }
1227
1228 unsafe fn discard_texture(&self, texture: super::SurfaceTexture) {
1229 unsafe {
1230 self.swapchain
1231 .write()
1232 .as_mut()
1233 .unwrap()
1234 .discard_texture(texture)
1235 .unwrap()
1236 };
1237 }
1238}