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(
170 debug_assertions,
171 feature = "internal_error_panic",
172 not(target_vendor = "apple")
173 ))]
174 if level == log::Level::Error
175 && message_type.contains(vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION)
176 && !error_is_waived(cd.message_id_number)
177 && !cts_error_is_waived(cd.message_id_number)
178 {
179 use alloc::string::ToString as _;
180 panic!("{}", message.to_string());
181 }
182
183 vk::FALSE
184}
185
186#[cfg(all(
190 debug_assertions,
191 feature = "internal_error_panic",
192 not(target_vendor = "apple")
193))]
194fn error_is_waived(message_id_number: i32) -> bool {
195 const WAIVED_MESSAGE_IDS: &[i32] = &[
196 0x5c0ec5d6_u32 as i32,
201 ];
202
203 WAIVED_MESSAGE_IDS.contains(&message_id_number)
204}
205
206#[cfg(all(
211 debug_assertions,
212 feature = "internal_error_panic",
213 not(target_vendor = "apple")
214))]
215fn cts_error_is_waived(message_id_number: i32) -> bool {
216 use std::sync::LazyLock;
217
218 static WGPU_CTS_XTASK: LazyLock<bool> =
219 LazyLock::new(|| std::env::var_os("WGPU_CTS_XTASK").is_some());
220
221 if !*WGPU_CTS_XTASK {
222 return false;
223 }
224
225 const WAIVED_MESSAGE_IDS: &[i32] = &[
226 0x34d444b2_u32 as i32,
229 0x6b654496_u32 as i32,
232 0x82396078_u32 as i32,
235 0xa3614f8b_u32 as i32,
238 0xa4164ba5_u32 as i32,
241 0xb75da543_u32 as i32,
244 0xf6d454db_u32 as i32,
247 ];
248
249 WAIVED_MESSAGE_IDS.contains(&message_id_number)
250}
251
252impl super::DebugUtilsCreateInfo {
253 fn to_vk_create_info(&self) -> vk::DebugUtilsMessengerCreateInfoEXT<'_> {
254 let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*self.callback_data;
255 vk::DebugUtilsMessengerCreateInfoEXT::default()
256 .message_severity(self.severity)
257 .message_type(self.message_type)
258 .user_data(user_data_ptr as *mut _)
259 .pfn_user_callback(Some(debug_utils_messenger_callback))
260 }
261}
262
263impl super::InstanceShared {
264 pub fn entry(&self) -> &ash::Entry {
265 &self.entry
266 }
267
268 pub fn raw_instance(&self) -> &ash::Instance {
269 &self.raw
270 }
271
272 pub fn instance_api_version(&self) -> u32 {
273 self.instance_api_version
274 }
275
276 pub fn extensions(&self) -> &[&'static CStr] {
277 &self.extensions[..]
278 }
279}
280
281impl super::Instance {
282 pub fn shared_instance(&self) -> &super::InstanceShared {
283 &self.shared
284 }
285
286 fn enumerate_instance_extension_properties(
287 entry: &ash::Entry,
288 layer_name: Option<&CStr>,
289 ) -> Result<Vec<vk::ExtensionProperties>, crate::InstanceError> {
290 let instance_extensions = {
291 profiling::scope!("vkEnumerateInstanceExtensionProperties");
292 unsafe { entry.enumerate_instance_extension_properties(layer_name) }
293 };
294 instance_extensions.map_err(|e| {
295 crate::InstanceError::with_source(
296 String::from("enumerate_instance_extension_properties() failed"),
297 e,
298 )
299 })
300 }
301
302 pub fn desired_extensions(
316 entry: &ash::Entry,
317 _instance_api_version: u32,
318 flags: wgt::InstanceFlags,
319 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
320 let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?;
321
322 let mut extensions: Vec<&'static CStr> = Vec::new();
324
325 extensions.push(khr::surface::NAME);
327
328 if cfg!(all(
330 unix,
331 not(target_os = "android"),
332 not(target_os = "macos"),
333 not(target_env = "ohos")
336 )) {
337 extensions.push(khr::xlib_surface::NAME);
339 extensions.push(khr::xcb_surface::NAME);
341 extensions.push(khr::wayland_surface::NAME);
343 }
344 if cfg!(target_os = "android") {
345 extensions.push(khr::android_surface::NAME);
347 }
348 #[cfg(target_env = "ohos")]
349 {
350 extensions.push(OHOS_SURFACE_EXTENSION_NAME);
352 }
353 if cfg!(target_os = "windows") {
354 extensions.push(khr::win32_surface::NAME);
356 }
357 if cfg!(target_os = "macos") {
358 extensions.push(ext::metal_surface::NAME);
360 extensions.push(khr::portability_enumeration::NAME);
361 }
362 if cfg!(drm) {
363 extensions.push(ext::acquire_drm_display::NAME);
365 extensions.push(ext::direct_mode_display::NAME);
366 extensions.push(khr::display::NAME);
367 extensions.push(khr::get_physical_device_properties2::NAME);
368 extensions.push(khr::get_display_properties2::NAME);
369 }
370
371 if flags.contains(wgt::InstanceFlags::DEBUG) {
372 extensions.push(ext::debug_utils::NAME);
374 }
375
376 extensions.push(ext::swapchain_colorspace::NAME);
379
380 extensions.push(khr::get_physical_device_properties2::NAME);
384
385 extensions.retain(|&ext| {
387 if instance_extensions
388 .iter()
389 .any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext))
390 {
391 true
392 } else {
393 log::debug!("Unable to find extension: {}", ext.to_string_lossy());
394 false
395 }
396 });
397 Ok(extensions)
398 }
399
400 #[allow(clippy::too_many_arguments)]
413 pub unsafe fn from_raw(
414 entry: ash::Entry,
415 raw_instance: ash::Instance,
416 instance_api_version: u32,
417 android_sdk_version: u32,
418 debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
419 extensions: Vec<&'static CStr>,
420 flags: wgt::InstanceFlags,
421 memory_budget_thresholds: wgt::MemoryBudgetThresholds,
422 has_nv_optimus: bool,
423 drop_callback: Option<crate::DropCallback>,
424 ) -> Result<Self, crate::InstanceError> {
425 log::debug!("Instance version: 0x{instance_api_version:x}");
426
427 let debug_utils = if let Some(debug_utils_create_info) = debug_utils_create_info {
428 if extensions.contains(&ext::debug_utils::NAME) {
429 log::debug!("Enabling debug utils");
430
431 let extension = ext::debug_utils::Instance::new(&entry, &raw_instance);
432 let vk_info = debug_utils_create_info.to_vk_create_info();
433 let messenger =
434 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
435
436 Some(super::DebugUtils {
437 extension,
438 messenger,
439 callback_data: debug_utils_create_info.callback_data,
440 })
441 } else {
442 log::debug!("Debug utils not enabled: extension not listed");
443 None
444 }
445 } else {
446 log::debug!(
447 "Debug utils not enabled: \
448 debug_utils_user_data not passed to Instance::from_raw"
449 );
450 None
451 };
452
453 let get_physical_device_properties =
454 if extensions.contains(&khr::get_physical_device_properties2::NAME) {
455 log::debug!("Enabling device properties2");
456 Some(khr::get_physical_device_properties2::Instance::new(
457 &entry,
458 &raw_instance,
459 ))
460 } else {
461 None
462 };
463
464 let drop_guard = crate::DropGuard::from_option(drop_callback);
465
466 Ok(Self {
467 shared: Arc::new(super::InstanceShared {
468 raw: raw_instance,
469 extensions,
470 drop_guard,
471 flags,
472 memory_budget_thresholds,
473 debug_utils,
474 get_physical_device_properties,
475 entry,
476 has_nv_optimus,
477 instance_api_version,
478 android_sdk_version,
479 }),
480 })
481 }
482
483 fn create_surface_from_xlib(
484 &self,
485 dpy: *mut vk::Display,
486 window: vk::Window,
487 ) -> Result<super::Surface, crate::InstanceError> {
488 if !self.shared.extensions.contains(&khr::xlib_surface::NAME) {
489 return Err(crate::InstanceError::new(String::from(
490 "Vulkan driver does not support VK_KHR_xlib_surface",
491 )));
492 }
493
494 let surface = {
495 let xlib_loader =
496 khr::xlib_surface::Instance::new(&self.shared.entry, &self.shared.raw);
497 let info = vk::XlibSurfaceCreateInfoKHR::default()
498 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
499 .window(window)
500 .dpy(dpy);
501
502 unsafe { xlib_loader.create_xlib_surface(&info, None) }
503 }
504 .map_err(|err| {
505 crate::InstanceError::with_source(
506 String::from("XlibSurface::create_xlib_surface() failed"),
507 err,
508 )
509 })?;
510
511 Ok(self.create_surface_from_vk_surface_khr(surface, None))
512 }
513
514 fn create_surface_from_xcb(
515 &self,
516 connection: *mut vk::xcb_connection_t,
517 window: vk::xcb_window_t,
518 ) -> Result<super::Surface, crate::InstanceError> {
519 if !self.shared.extensions.contains(&khr::xcb_surface::NAME) {
520 return Err(crate::InstanceError::new(String::from(
521 "Vulkan driver does not support VK_KHR_xcb_surface",
522 )));
523 }
524
525 let surface = {
526 let xcb_loader = khr::xcb_surface::Instance::new(&self.shared.entry, &self.shared.raw);
527 let info = vk::XcbSurfaceCreateInfoKHR::default()
528 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
529 .window(window)
530 .connection(connection);
531
532 unsafe { xcb_loader.create_xcb_surface(&info, None) }
533 }
534 .map_err(|err| {
535 crate::InstanceError::with_source(
536 String::from("XcbSurface::create_xcb_surface() failed"),
537 err,
538 )
539 })?;
540
541 Ok(self.create_surface_from_vk_surface_khr(surface, None))
542 }
543
544 fn create_surface_from_wayland(
545 &self,
546 display: *mut vk::wl_display,
547 surface: *mut vk::wl_surface,
548 ) -> Result<super::Surface, crate::InstanceError> {
549 if !self.shared.extensions.contains(&khr::wayland_surface::NAME) {
550 return Err(crate::InstanceError::new(String::from(
551 "Vulkan driver does not support VK_KHR_wayland_surface",
552 )));
553 }
554
555 let surface = {
556 let w_loader =
557 khr::wayland_surface::Instance::new(&self.shared.entry, &self.shared.raw);
558 let info = vk::WaylandSurfaceCreateInfoKHR::default()
559 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
560 .display(display)
561 .surface(surface);
562
563 unsafe { w_loader.create_wayland_surface(&info, None) }
564 }
565 .map_err(|err| {
566 crate::InstanceError::with_source(String::from("WaylandSurface failed"), err)
567 })?;
568
569 Ok(self.create_surface_from_vk_surface_khr(surface, None))
570 }
571
572 fn create_surface_android(
573 &self,
574 window: *mut vk::ANativeWindow,
575 ) -> Result<super::Surface, crate::InstanceError> {
576 if !self.shared.extensions.contains(&khr::android_surface::NAME) {
577 return Err(crate::InstanceError::new(String::from(
578 "Vulkan driver does not support VK_KHR_android_surface",
579 )));
580 }
581
582 let surface = {
583 let a_loader =
584 khr::android_surface::Instance::new(&self.shared.entry, &self.shared.raw);
585 let info = vk::AndroidSurfaceCreateInfoKHR::default()
586 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
587 .window(window);
588
589 unsafe { a_loader.create_android_surface(&info, None) }
590 }
591 .map_err(|err| {
592 crate::InstanceError::with_source(String::from("AndroidSurface failed"), err)
593 })?;
594
595 Ok(self.create_surface_from_vk_surface_khr(surface, None))
596 }
597
598 #[cfg(target_env = "ohos")]
607 fn create_surface_ohos(
608 &self,
609 window: *mut c_void,
610 ) -> Result<super::Surface, crate::InstanceError> {
611 #[repr(C)]
614 struct VkSurfaceCreateInfoOHOS {
615 s_type: vk::StructureType,
616 p_next: *const c_void,
617 flags: vk::Flags,
618 window: *mut c_void,
619 }
620
621 const S_TYPE_SURFACE_CREATE_INFO_OHOS: vk::StructureType =
624 vk::StructureType::from_raw(1000685000);
625
626 type PfnCreateSurfaceOHOS = unsafe extern "system" fn(
629 vk::Instance,
630 *const VkSurfaceCreateInfoOHOS,
631 *const vk::AllocationCallbacks,
632 *mut vk::SurfaceKHR,
633 ) -> vk::Result;
634
635 if !self
636 .shared
637 .extensions
638 .contains(&OHOS_SURFACE_EXTENSION_NAME)
639 {
640 return Err(crate::InstanceError::new(String::from(
641 "Vulkan driver does not support VK_OHOS_surface",
642 )));
643 }
644
645 let raw_instance = self.shared.raw.handle();
646
647 let create = unsafe {
652 self.shared
653 .entry
654 .get_instance_proc_addr(raw_instance, c"vkCreateSurfaceOHOS".as_ptr())
655 };
656 let create =
657 unsafe { core::mem::transmute::<vk::PFN_vkVoidFunction, Option<PfnCreateSurfaceOHOS>>(create) };
660 let Some(create) = create else {
661 return Err(crate::InstanceError::new(String::from(
662 "vkCreateSurfaceOHOS not exposed by Vulkan driver",
663 )));
664 };
665
666 let info = VkSurfaceCreateInfoOHOS {
667 s_type: S_TYPE_SURFACE_CREATE_INFO_OHOS,
668 p_next: core::ptr::null(),
669 flags: 0,
670 window,
671 };
672 let mut surface = vk::SurfaceKHR::null();
673 let result = unsafe { create(raw_instance, &info, core::ptr::null(), &mut surface) };
679 if result != vk::Result::SUCCESS {
680 return Err(crate::InstanceError::new(format!(
681 "vkCreateSurfaceOHOS failed: {result:?}"
682 )));
683 }
684
685 Ok(self.create_surface_from_vk_surface_khr(surface, None))
686 }
687
688 fn create_surface_from_hwnd(
689 &self,
690 hinstance: vk::HINSTANCE,
691 hwnd: vk::HWND,
692 ) -> Result<super::Surface, crate::InstanceError> {
693 if !self.shared.extensions.contains(&khr::win32_surface::NAME) {
694 return Err(crate::InstanceError::new(String::from(
695 "Vulkan driver does not support VK_KHR_win32_surface",
696 )));
697 }
698
699 let surface = {
700 let info = vk::Win32SurfaceCreateInfoKHR::default()
701 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
702 .hinstance(hinstance)
703 .hwnd(hwnd);
704 let win32_loader =
705 khr::win32_surface::Instance::new(&self.shared.entry, &self.shared.raw);
706 unsafe { win32_loader.create_win32_surface(&info, None) }
707 }
708 .map_err(|err| {
709 crate::InstanceError::with_source(String::from("Unable to create Win32 surface"), err)
710 })?;
711
712 #[cfg(windows)]
715 let window_handle = Some(crate::vulkan::swapchain::WindowHandle(
716 windows::Win32::Foundation::HWND(hwnd as *mut c_void),
717 ));
718 #[cfg(not(windows))]
719 let window_handle: Option<crate::vulkan::swapchain::WindowHandle> = None;
720 Ok(self.create_surface_from_vk_surface_khr(surface, window_handle))
721 }
722
723 #[cfg(target_vendor = "apple")]
724 fn create_surface_from_layer(
725 &self,
726 layer: raw_window_metal::Layer,
727 ) -> Result<super::Surface, crate::InstanceError> {
728 if !self.shared.extensions.contains(&ext::metal_surface::NAME) {
729 return Err(crate::InstanceError::new(String::from(
730 "Vulkan driver does not support VK_EXT_metal_surface",
731 )));
732 }
733
734 let surface = {
737 let metal_loader =
738 ext::metal_surface::Instance::new(&self.shared.entry, &self.shared.raw);
739 let vk_info = vk::MetalSurfaceCreateInfoEXT::default()
740 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
741 .layer(layer.as_ptr().as_ptr());
742
743 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
744 };
745
746 Ok(self.create_surface_from_vk_surface_khr(surface, None))
747 }
748
749 pub(super) fn create_surface_from_vk_surface_khr(
750 &self,
751 surface: vk::SurfaceKHR,
752 hwnd: Option<crate::vulkan::swapchain::WindowHandle>,
753 ) -> super::Surface {
754 let native_surface =
755 crate::vulkan::swapchain::NativeSurface::from_vk_surface_khr(self, surface, hwnd);
756
757 super::Surface {
758 swapchain: RwLock::new(None),
759 inner: Box::new(native_surface),
760 }
761 }
762
763 pub unsafe fn init_with_callback(
772 desc: &crate::InstanceDescriptor<'_>,
773 callback: Option<Box<super::CreateInstanceCallback>>,
774 ) -> Result<Self, crate::InstanceError> {
775 profiling::scope!("Init Vulkan Backend");
776
777 let entry = unsafe {
778 profiling::scope!("Load vk library");
779 #[cfg(target_env = "ohos")]
782 let loaded = ash::Entry::load_from("libvulkan.so");
783 #[cfg(not(target_env = "ohos"))]
784 let loaded = ash::Entry::load();
785 loaded
786 }
787 .map_err(|err| {
788 crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
789 })?;
790 let version = {
791 profiling::scope!("vkEnumerateInstanceVersion");
792 unsafe { entry.try_enumerate_instance_version() }
793 };
794 let instance_api_version = match version {
795 Ok(Some(version)) => version,
797 Ok(None) => vk::API_VERSION_1_0,
798 Err(err) => {
799 return Err(crate::InstanceError::with_source(
800 String::from("try_enumerate_instance_version() failed"),
801 err,
802 ));
803 }
804 };
805
806 let app_name = CString::new(desc.name).unwrap();
807 let app_info = vk::ApplicationInfo::default()
808 .application_name(app_name.as_c_str())
809 .application_version(1)
810 .engine_name(c"wgpu-hal")
811 .engine_version(2)
812 .api_version(
813 if instance_api_version < vk::API_VERSION_1_1 {
815 vk::API_VERSION_1_0
816 } else {
817 vk::API_VERSION_1_3
826 },
827 );
828
829 let mut extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
830 let mut create_info = vk::InstanceCreateInfo::default();
831
832 if let Some(callback) = callback {
833 callback(super::CreateInstanceCallbackArgs {
834 extensions: &mut extensions,
835 create_info: &mut create_info,
836 entry: &entry,
837 _phantom: PhantomData,
838 });
839 }
840
841 let instance_layers = {
842 profiling::scope!("vkEnumerateInstanceLayerProperties");
843 unsafe { entry.enumerate_instance_layer_properties() }
844 };
845 let instance_layers = instance_layers.map_err(|e| {
846 log::debug!("enumerate_instance_layer_properties: {e:?}");
847 crate::InstanceError::with_source(
848 String::from("enumerate_instance_layer_properties() failed"),
849 e,
850 )
851 })?;
852
853 fn find_layer<'layers>(
854 instance_layers: &'layers [vk::LayerProperties],
855 name: &CStr,
856 ) -> Option<&'layers vk::LayerProperties> {
857 instance_layers
858 .iter()
859 .find(|inst_layer| inst_layer.layer_name_as_c_str() == Ok(name))
860 }
861
862 let validation_layer_name = c"VK_LAYER_KHRONOS_validation";
863 let validation_layer_properties = find_layer(&instance_layers, validation_layer_name);
864
865 let validation_features_are_enabled = if validation_layer_properties.is_some() {
868 let exts =
870 Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?;
871 let mut ext_names = exts
873 .iter()
874 .filter_map(|ext| ext.extension_name_as_c_str().ok());
875 ext_names.any(|ext_name| ext_name == ext::validation_features::NAME)
877 } else {
878 false
879 };
880
881 let should_enable_gpu_based_validation = desc
882 .flags
883 .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
884 && validation_features_are_enabled;
885
886 let has_nv_optimus = find_layer(&instance_layers, c"VK_LAYER_NV_optimus").is_some();
887
888 let has_obs_layer = find_layer(&instance_layers, c"VK_LAYER_OBS_HOOK").is_some();
889
890 let mut layers: Vec<&'static CStr> = Vec::new();
891
892 let has_debug_extension = extensions.contains(&ext::debug_utils::NAME);
893 let mut debug_user_data = has_debug_extension.then(|| {
894 Box::new(super::DebugUtilsMessengerUserData {
897 validation_layer_properties: None,
898 has_obs_layer,
899 })
900 });
901
902 if desc.flags.intersects(wgt::InstanceFlags::VALIDATION)
904 || should_enable_gpu_based_validation
905 {
906 if let Some(layer_properties) = validation_layer_properties {
907 layers.push(validation_layer_name);
908
909 if let Some(debug_user_data) = debug_user_data.as_mut() {
910 debug_user_data.validation_layer_properties =
911 Some(super::ValidationLayerProperties {
912 layer_description: layer_properties
913 .description_as_c_str()
914 .unwrap()
915 .to_owned(),
916 layer_spec_version: layer_properties.spec_version,
917 });
918 }
919 } else {
920 log::debug!(
921 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
922 validation_layer_name.to_string_lossy()
923 );
924 }
925 }
926 let mut debug_utils = if let Some(callback_data) = debug_user_data {
927 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
929 if log::max_level() >= log::LevelFilter::Debug {
930 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
931 }
932 if log::max_level() >= log::LevelFilter::Info {
933 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
934 }
935 if log::max_level() >= log::LevelFilter::Warn {
936 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
937 }
938
939 let message_type = vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
940 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
941 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
942
943 let create_info = super::DebugUtilsCreateInfo {
944 severity,
945 message_type,
946 callback_data,
947 };
948
949 Some(create_info)
950 } else {
951 None
952 };
953
954 #[cfg(target_os = "android")]
955 let android_sdk_version = {
956 let properties = android_system_properties::AndroidSystemProperties::new();
957 if let Some(val) = properties.get("ro.build.version.sdk") {
959 match val.parse::<u32>() {
960 Ok(sdk_ver) => sdk_ver,
961 Err(err) => {
962 log::error!(
963 concat!(
964 "Couldn't parse Android's ",
965 "ro.build.version.sdk system property ({}): {}",
966 ),
967 val,
968 err,
969 );
970 0
971 }
972 }
973 } else {
974 log::error!("Couldn't read Android's ro.build.version.sdk system property");
975 0
976 }
977 };
978 #[cfg(not(target_os = "android"))]
979 let android_sdk_version = 0;
980
981 let mut flags = vk::InstanceCreateFlags::empty();
982
983 if extensions.contains(&khr::portability_enumeration::NAME) {
987 flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
988 }
989 let vk_instance = {
990 let str_pointers = layers
991 .iter()
992 .chain(extensions.iter())
993 .map(|&s: &&'static _| {
994 s.as_ptr()
996 })
997 .collect::<Vec<_>>();
998
999 create_info = create_info
1000 .flags(flags)
1001 .application_info(&app_info)
1002 .enabled_layer_names(&str_pointers[..layers.len()])
1003 .enabled_extension_names(&str_pointers[layers.len()..]);
1004
1005 let mut debug_utils_create_info = debug_utils
1006 .as_mut()
1007 .map(|create_info| create_info.to_vk_create_info());
1008 if let Some(debug_utils_create_info) = debug_utils_create_info.as_mut() {
1009 create_info = create_info.push_next(debug_utils_create_info);
1010 }
1011
1012 let mut validation_features;
1014 let mut validation_feature_list: ArrayVec<_, 3>;
1015 if validation_features_are_enabled {
1016 validation_feature_list = ArrayVec::new();
1017
1018 validation_feature_list
1020 .push(vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION);
1021
1022 if should_enable_gpu_based_validation {
1024 validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED);
1025 validation_feature_list
1026 .push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT);
1027 }
1028
1029 validation_features = vk::ValidationFeaturesEXT::default()
1030 .enabled_validation_features(&validation_feature_list);
1031 create_info = create_info.push_next(&mut validation_features);
1032 }
1033
1034 unsafe {
1035 profiling::scope!("vkCreateInstance");
1036 entry.create_instance(&create_info, None)
1037 }
1038 .map_err(|e| {
1039 crate::InstanceError::with_source(
1040 String::from("Entry::create_instance() failed"),
1041 e,
1042 )
1043 })?
1044 };
1045
1046 unsafe {
1047 Self::from_raw(
1048 entry,
1049 vk_instance,
1050 instance_api_version,
1051 android_sdk_version,
1052 debug_utils,
1053 extensions,
1054 desc.flags,
1055 desc.memory_budget_thresholds,
1056 has_nv_optimus,
1057 None,
1058 )
1059 }
1060 }
1061}
1062
1063impl Drop for super::InstanceShared {
1064 fn drop(&mut self) {
1065 unsafe {
1066 let _du = self.debug_utils.take().inspect(|du| {
1068 du.extension
1069 .destroy_debug_utils_messenger(du.messenger, None);
1070 });
1071 if self.drop_guard.is_none() {
1072 self.raw.destroy_instance(None);
1073 }
1074 }
1075 }
1076}
1077
1078impl crate::Instance for super::Instance {
1079 type A = super::Api;
1080
1081 unsafe fn init(desc: &crate::InstanceDescriptor<'_>) -> Result<Self, crate::InstanceError> {
1082 unsafe { Self::init_with_callback(desc, None) }
1083 }
1084
1085 unsafe fn create_surface(
1086 &self,
1087 display_handle: raw_window_handle::RawDisplayHandle,
1088 window_handle: raw_window_handle::RawWindowHandle,
1089 ) -> Result<super::Surface, crate::InstanceError> {
1090 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
1091
1092 match (window_handle, display_handle) {
1095 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
1096 self.create_surface_from_wayland(display.display.as_ptr(), handle.surface.as_ptr())
1097 }
1098 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
1099 let display = display.display.expect("Display pointer is not set.");
1100 self.create_surface_from_xlib(display.as_ptr(), handle.window)
1101 }
1102 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
1103 let connection = display.connection.expect("Pointer to X-Server is not set.");
1104 self.create_surface_from_xcb(connection.as_ptr(), handle.window.get())
1105 }
1106 #[cfg(drm)]
1107 (Rwh::Drm(handle), Rdh::Drm(display)) => {
1108 self.create_surface_from_drm_plane(display.fd, handle.plane)
1109 }
1110 (Rwh::AndroidNdk(handle), _) => {
1111 self.create_surface_android(handle.a_native_window.as_ptr())
1112 }
1113 #[cfg(target_env = "ohos")]
1114 (Rwh::OhosNdk(handle), _) => self.create_surface_ohos(handle.native_window.as_ptr()),
1115 (Rwh::Win32(handle), _) => {
1116 let hinstance = handle.hinstance.ok_or_else(|| {
1117 crate::InstanceError::new(String::from(
1118 "Vulkan requires raw-window-handle's Win32::hinstance to be set",
1119 ))
1120 })?;
1121 self.create_surface_from_hwnd(hinstance.get(), handle.hwnd.get())
1122 }
1123 #[cfg(target_vendor = "apple")]
1124 (Rwh::AppKit(handle), _)
1125 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
1126 {
1127 let layer = unsafe { raw_window_metal::Layer::from_ns_view(handle.ns_view) };
1128 self.create_surface_from_layer(layer)
1129 }
1130 #[cfg(target_vendor = "apple")]
1131 (Rwh::UiKit(handle), _)
1132 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
1133 {
1134 let layer = unsafe { raw_window_metal::Layer::from_ui_view(handle.ui_view) };
1135 self.create_surface_from_layer(layer)
1136 }
1137 (_, _) => Err(crate::InstanceError::new(format!(
1138 "window handle {window_handle:?} is not a Vulkan-compatible handle"
1139 ))),
1140 }
1141 }
1142
1143 unsafe fn enumerate_adapters(
1144 &self,
1145 _surface_hint: Option<&super::Surface>,
1146 ) -> Vec<crate::ExposedAdapter<super::Api>> {
1147 use crate::auxil::db;
1148
1149 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
1150 Ok(devices) => devices,
1151 Err(err) => {
1152 log::error!("enumerate_adapters: {err}");
1153 Vec::new()
1154 }
1155 };
1156
1157 let mut exposed_adapters = raw_devices
1158 .into_iter()
1159 .flat_map(|device| self.expose_adapter(device))
1160 .collect::<Vec<_>>();
1161
1162 let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| {
1164 exposed.info.device_type == wgt::DeviceType::DiscreteGpu
1165 && exposed.info.vendor == db::nvidia::VENDOR
1166 });
1167 if cfg!(target_os = "linux") && has_nvidia_dgpu && self.shared.has_nv_optimus {
1168 for exposed in exposed_adapters.iter_mut() {
1169 if exposed.info.device_type == wgt::DeviceType::IntegratedGpu
1170 && exposed.info.vendor == db::intel::VENDOR
1171 {
1172 if let Some(version) = exposed.info.driver_info.split_once("Mesa ").map(|s| {
1174 let mut components = s.1.split('.');
1175 let major = components.next().and_then(|s| u8::from_str(s).ok());
1176 let minor = components.next().and_then(|s| u8::from_str(s).ok());
1177 if let (Some(major), Some(minor)) = (major, minor) {
1178 (major, minor)
1179 } else {
1180 (0, 0)
1181 }
1182 }) {
1183 if version < (21, 2) {
1184 log::debug!(
1186 concat!(
1187 "Disabling presentation on '{}' (id {:?}) ",
1188 "due to NV Optimus and Intel Mesa < v21.2"
1189 ),
1190 exposed.info.name,
1191 exposed.adapter.raw
1192 );
1193 exposed.adapter.private_caps.can_present = false;
1194 }
1195 }
1196 }
1197 }
1198 }
1199
1200 exposed_adapters
1201 }
1202}
1203
1204impl crate::Surface for super::Surface {
1205 type A = super::Api;
1206
1207 unsafe fn configure(
1208 &self,
1209 device: &super::Device,
1210 config: &crate::SurfaceConfiguration,
1211 ) -> Result<(), crate::SurfaceError> {
1212 let mut swap_chain = self.swapchain.write();
1214
1215 let mut old = swap_chain.take();
1216 if let Some(ref mut old) = old {
1217 unsafe { old.release_resources(device) };
1218 }
1219
1220 let swapchain = unsafe { self.inner.create_swapchain(device, config, old)? };
1221 *swap_chain = Some(swapchain);
1222
1223 Ok(())
1224 }
1225
1226 unsafe fn unconfigure(&self, device: &super::Device) {
1227 if let Some(mut sc) = self.swapchain.write().take() {
1228 unsafe { sc.release_resources(device) };
1230 }
1231 }
1232
1233 unsafe fn acquire_texture(
1234 &self,
1235 timeout: Option<core::time::Duration>,
1236 fence: &super::Fence,
1237 ) -> Result<crate::AcquiredSurfaceTexture<super::Api>, crate::SurfaceError> {
1238 let mut swapchain = self.swapchain.write();
1239 let swapchain = swapchain.as_mut().unwrap();
1240
1241 unsafe { swapchain.acquire(timeout, fence) }
1242 }
1243
1244 unsafe fn discard_texture(&self, texture: super::SurfaceTexture) {
1245 unsafe {
1246 self.swapchain
1247 .write()
1248 .as_mut()
1249 .unwrap()
1250 .discard_texture(texture)
1251 .unwrap()
1252 };
1253 }
1254}