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 wgpu_sync::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 const DEBUG_PRINTF_MESSAGE_ID: i32 = 0x4fe1fef9;
92 if cd.message_id_number == DEBUG_PRINTF_MESSAGE_ID {
93 let message =
95 unsafe { cd.message_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
96
97 log::info!("[shader debugPrintf] {}", message);
98
99 return vk::FALSE;
100 }
101
102 let level = match message_severity {
103 vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => log::Level::Trace,
106 vk::DebugUtilsMessageSeverityFlagsEXT::INFO => log::Level::Debug,
107 vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => log::Level::Warn,
108 vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => log::Level::Error,
109 _ => log::Level::Warn,
110 };
111
112 let message_id_name =
113 unsafe { cd.message_id_name_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
114 let message = unsafe { cd.message_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
115
116 let _ = std::panic::catch_unwind(|| {
117 log::log!(
118 level,
119 "{:?} [{} (0x{:x})]\n\t{}",
120 message_type,
121 message_id_name,
122 cd.message_id_number,
123 message,
124 );
125 });
126
127 if cd.queue_label_count != 0 {
128 let labels =
129 unsafe { slice::from_raw_parts(cd.p_queue_labels, cd.queue_label_count as usize) };
130 let names = labels
131 .iter()
132 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
133 .collect::<Vec<_>>();
134
135 let _ = std::panic::catch_unwind(|| {
136 log::log!(level, "\tqueues: {}", names.join(", "));
137 });
138 }
139
140 if cd.cmd_buf_label_count != 0 {
141 let labels =
142 unsafe { slice::from_raw_parts(cd.p_cmd_buf_labels, cd.cmd_buf_label_count as usize) };
143 let names = labels
144 .iter()
145 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
146 .collect::<Vec<_>>();
147
148 let _ = std::panic::catch_unwind(|| {
149 log::log!(level, "\tcommand buffers: {}", names.join(", "));
150 });
151 }
152
153 if cd.object_count != 0 {
154 let labels = unsafe { slice::from_raw_parts(cd.p_objects, cd.object_count as usize) };
155 let names = labels
157 .iter()
158 .map(|obj_info| {
159 let name = unsafe { obj_info.object_name_as_c_str() }
160 .map_or(Cow::Borrowed("?"), CStr::to_string_lossy);
161
162 format!(
163 "(type: {:?}, hndl: 0x{:x}, name: {})",
164 obj_info.object_type, obj_info.object_handle, name
165 )
166 })
167 .collect::<Vec<_>>();
168 let _ = std::panic::catch_unwind(|| {
169 log::log!(level, "\tobjects: {}", names.join(", "));
170 });
171 }
172
173 #[cfg(feature = "validation_canary")]
174 if cfg!(debug_assertions) && level == log::Level::Error {
175 use alloc::string::ToString as _;
176
177 crate::VALIDATION_CANARY.add(message.to_string());
179 }
180
181 #[cfg(all(
186 debug_assertions,
187 feature = "internal_error_panic",
188 not(target_vendor = "apple")
189 ))]
190 if level == log::Level::Error
191 && message_type.contains(vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION)
192 && !cts_error_is_waived(cd.message_id_number)
193 {
194 use alloc::string::ToString as _;
195 panic!("{}", message.to_string());
196 }
197
198 vk::FALSE
199}
200
201#[cfg(all(
206 debug_assertions,
207 feature = "internal_error_panic",
208 not(target_vendor = "apple")
209))]
210fn cts_error_is_waived(message_id_number: i32) -> bool {
211 use wgpu_sync::Lazy;
212
213 static WGPU_CTS_XTASK: Lazy<bool> = Lazy::new(|| std::env::var_os("WGPU_CTS_XTASK").is_some());
214
215 if !*WGPU_CTS_XTASK {
216 return false;
217 }
218
219 const WAIVED_MESSAGE_IDS: &[i32] = &[
220 0x34d444b2_u32 as i32,
223 0x6b654496_u32 as i32,
226 0x82396078_u32 as i32,
229 0xa3614f8b_u32 as i32,
232 0xa4164ba5_u32 as i32,
235 0xb75da543_u32 as i32,
238 0xf6d454db_u32 as i32,
241 ];
242
243 WAIVED_MESSAGE_IDS.contains(&message_id_number)
244}
245
246impl super::DebugUtilsCreateInfo {
247 fn to_vk_create_info(&self) -> vk::DebugUtilsMessengerCreateInfoEXT<'_> {
248 let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*self.callback_data;
249 vk::DebugUtilsMessengerCreateInfoEXT::default()
250 .message_severity(self.severity)
251 .message_type(self.message_type)
252 .user_data(user_data_ptr as *mut _)
253 .pfn_user_callback(Some(debug_utils_messenger_callback))
254 }
255}
256
257impl super::InstanceShared {
258 pub fn entry(&self) -> &ash::Entry {
259 &self.entry
260 }
261
262 pub fn raw_instance(&self) -> &ash::Instance {
263 &self.raw
264 }
265
266 pub fn instance_api_version(&self) -> u32 {
267 self.instance_api_version
268 }
269
270 pub fn extensions(&self) -> &[&'static CStr] {
271 &self.extensions[..]
272 }
273}
274
275impl super::Instance {
276 pub fn shared_instance(&self) -> &super::InstanceShared {
277 &self.shared
278 }
279
280 fn enumerate_instance_extension_properties(
281 entry: &ash::Entry,
282 layer_name: Option<&CStr>,
283 ) -> Result<Vec<vk::ExtensionProperties>, crate::InstanceError> {
284 let instance_extensions = {
285 profiling::scope!("vkEnumerateInstanceExtensionProperties");
286 unsafe { entry.enumerate_instance_extension_properties(layer_name) }
287 };
288 instance_extensions.map_err(|e| {
289 crate::InstanceError::with_source(
290 String::from("enumerate_instance_extension_properties() failed"),
291 e,
292 )
293 })
294 }
295
296 pub fn desired_extensions(
310 entry: &ash::Entry,
311 _instance_api_version: u32,
312 flags: wgt::InstanceFlags,
313 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
314 let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?;
315
316 let mut extensions: Vec<&'static CStr> = Vec::new();
318
319 extensions.push(khr::surface::NAME);
321
322 if cfg!(all(
324 unix,
325 not(target_os = "android"),
326 not(target_os = "macos"),
327 not(target_env = "ohos")
330 )) {
331 extensions.push(khr::xlib_surface::NAME);
333 extensions.push(khr::xcb_surface::NAME);
335 extensions.push(khr::wayland_surface::NAME);
337 }
338 if cfg!(target_os = "android") {
339 extensions.push(khr::android_surface::NAME);
341 }
342 #[cfg(target_env = "ohos")]
343 {
344 extensions.push(OHOS_SURFACE_EXTENSION_NAME);
346 }
347 if cfg!(target_os = "windows") {
348 extensions.push(khr::win32_surface::NAME);
350 }
351 if cfg!(target_os = "macos") {
352 extensions.push(ext::metal_surface::NAME);
354 extensions.push(khr::portability_enumeration::NAME);
355 }
356 if cfg!(drm) {
357 extensions.push(ext::acquire_drm_display::NAME);
359 extensions.push(ext::direct_mode_display::NAME);
360 extensions.push(khr::display::NAME);
361 extensions.push(khr::get_physical_device_properties2::NAME);
362 extensions.push(khr::get_display_properties2::NAME);
363 }
364
365 if flags.intersects(wgt::InstanceFlags::DEBUG | wgt::InstanceFlags::DEBUG_PRINTF) {
366 extensions.push(ext::debug_utils::NAME);
368 }
369
370 extensions.push(ext::swapchain_colorspace::NAME);
373
374 extensions.push(khr::get_physical_device_properties2::NAME);
378
379 extensions.retain(|&ext| {
381 if instance_extensions
382 .iter()
383 .any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext))
384 {
385 true
386 } else {
387 log::debug!("Unable to find extension: {}", ext.to_string_lossy());
388 false
389 }
390 });
391 Ok(extensions)
392 }
393
394 #[allow(clippy::too_many_arguments)]
407 pub unsafe fn from_raw(
408 entry: ash::Entry,
409 raw_instance: ash::Instance,
410 instance_api_version: u32,
411 android_sdk_version: u32,
412 debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
413 extensions: Vec<&'static CStr>,
414 flags: wgt::InstanceFlags,
415 memory_budget_thresholds: wgt::MemoryBudgetThresholds,
416 has_nv_optimus: bool,
417 drop_callback: Option<crate::DropCallback>,
418 ) -> Result<Self, crate::InstanceError> {
419 log::debug!("Instance version: 0x{instance_api_version:x}");
420
421 let debug_utils = if let Some(debug_utils_create_info) = debug_utils_create_info {
422 if extensions.contains(&ext::debug_utils::NAME) {
423 log::debug!("Enabling debug utils");
424
425 let extension = ext::debug_utils::Instance::new(&entry, &raw_instance);
426 let vk_info = debug_utils_create_info.to_vk_create_info();
427 let messenger =
428 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
429
430 Some(super::DebugUtils {
431 extension,
432 messenger,
433 callback_data: debug_utils_create_info.callback_data,
434 })
435 } else {
436 log::debug!("Debug utils not enabled: extension not listed");
437 None
438 }
439 } else {
440 log::debug!(
441 "Debug utils not enabled: \
442 debug_utils_user_data not passed to Instance::from_raw"
443 );
444 None
445 };
446
447 let get_physical_device_properties =
448 if extensions.contains(&khr::get_physical_device_properties2::NAME) {
449 log::debug!("Enabling device properties2");
450 Some(khr::get_physical_device_properties2::Instance::new(
451 &entry,
452 &raw_instance,
453 ))
454 } else {
455 None
456 };
457
458 let drop_guard = crate::DropGuard::from_option(drop_callback);
459
460 Ok(Self {
461 shared: Arc::new(super::InstanceShared {
462 raw: raw_instance,
463 extensions,
464 drop_guard,
465 flags,
466 memory_budget_thresholds,
467 debug_utils,
468 get_physical_device_properties,
469 entry,
470 has_nv_optimus,
471 instance_api_version,
472 android_sdk_version,
473 }),
474 })
475 }
476
477 fn create_surface_from_xlib(
478 &self,
479 dpy: *mut vk::Display,
480 window: vk::Window,
481 ) -> Result<super::Surface, crate::InstanceError> {
482 if !self.shared.extensions.contains(&khr::xlib_surface::NAME) {
483 return Err(crate::InstanceError::new(String::from(
484 "Vulkan driver does not support VK_KHR_xlib_surface",
485 )));
486 }
487
488 let surface = {
489 let xlib_loader =
490 khr::xlib_surface::Instance::new(&self.shared.entry, &self.shared.raw);
491 let info = vk::XlibSurfaceCreateInfoKHR::default()
492 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
493 .window(window)
494 .dpy(dpy);
495
496 unsafe { xlib_loader.create_xlib_surface(&info, None) }
497 }
498 .map_err(|err| {
499 crate::InstanceError::with_source(
500 String::from("XlibSurface::create_xlib_surface() failed"),
501 err,
502 )
503 })?;
504
505 Ok(self.create_surface_from_vk_surface_khr(surface, None))
506 }
507
508 fn create_surface_from_xcb(
509 &self,
510 connection: *mut vk::xcb_connection_t,
511 window: vk::xcb_window_t,
512 ) -> Result<super::Surface, crate::InstanceError> {
513 if !self.shared.extensions.contains(&khr::xcb_surface::NAME) {
514 return Err(crate::InstanceError::new(String::from(
515 "Vulkan driver does not support VK_KHR_xcb_surface",
516 )));
517 }
518
519 let surface = {
520 let xcb_loader = khr::xcb_surface::Instance::new(&self.shared.entry, &self.shared.raw);
521 let info = vk::XcbSurfaceCreateInfoKHR::default()
522 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
523 .window(window)
524 .connection(connection);
525
526 unsafe { xcb_loader.create_xcb_surface(&info, None) }
527 }
528 .map_err(|err| {
529 crate::InstanceError::with_source(
530 String::from("XcbSurface::create_xcb_surface() failed"),
531 err,
532 )
533 })?;
534
535 Ok(self.create_surface_from_vk_surface_khr(surface, None))
536 }
537
538 fn create_surface_from_wayland(
539 &self,
540 display: *mut vk::wl_display,
541 surface: *mut vk::wl_surface,
542 ) -> Result<super::Surface, crate::InstanceError> {
543 if !self.shared.extensions.contains(&khr::wayland_surface::NAME) {
544 return Err(crate::InstanceError::new(String::from(
545 "Vulkan driver does not support VK_KHR_wayland_surface",
546 )));
547 }
548
549 let surface = {
550 let w_loader =
551 khr::wayland_surface::Instance::new(&self.shared.entry, &self.shared.raw);
552 let info = vk::WaylandSurfaceCreateInfoKHR::default()
553 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
554 .display(display)
555 .surface(surface);
556
557 unsafe { w_loader.create_wayland_surface(&info, None) }
558 }
559 .map_err(|err| {
560 crate::InstanceError::with_source(String::from("WaylandSurface failed"), err)
561 })?;
562
563 Ok(self.create_surface_from_vk_surface_khr(surface, None))
564 }
565
566 fn create_surface_android(
567 &self,
568 window: *mut vk::ANativeWindow,
569 ) -> Result<super::Surface, crate::InstanceError> {
570 if !self.shared.extensions.contains(&khr::android_surface::NAME) {
571 return Err(crate::InstanceError::new(String::from(
572 "Vulkan driver does not support VK_KHR_android_surface",
573 )));
574 }
575
576 let surface = {
577 let a_loader =
578 khr::android_surface::Instance::new(&self.shared.entry, &self.shared.raw);
579 let info = vk::AndroidSurfaceCreateInfoKHR::default()
580 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
581 .window(window);
582
583 unsafe { a_loader.create_android_surface(&info, None) }
584 }
585 .map_err(|err| {
586 crate::InstanceError::with_source(String::from("AndroidSurface failed"), err)
587 })?;
588
589 Ok(self.create_surface_from_vk_surface_khr(surface, None))
590 }
591
592 #[cfg(target_env = "ohos")]
601 fn create_surface_ohos(
602 &self,
603 window: *mut c_void,
604 ) -> Result<super::Surface, crate::InstanceError> {
605 #[repr(C)]
608 struct VkSurfaceCreateInfoOHOS {
609 s_type: vk::StructureType,
610 p_next: *const c_void,
611 flags: vk::Flags,
612 window: *mut c_void,
613 }
614
615 const S_TYPE_SURFACE_CREATE_INFO_OHOS: vk::StructureType =
618 vk::StructureType::from_raw(1000685000);
619
620 type PfnCreateSurfaceOHOS = unsafe extern "system" fn(
623 vk::Instance,
624 *const VkSurfaceCreateInfoOHOS,
625 *const vk::AllocationCallbacks,
626 *mut vk::SurfaceKHR,
627 ) -> vk::Result;
628
629 if !self
630 .shared
631 .extensions
632 .contains(&OHOS_SURFACE_EXTENSION_NAME)
633 {
634 return Err(crate::InstanceError::new(String::from(
635 "Vulkan driver does not support VK_OHOS_surface",
636 )));
637 }
638
639 let raw_instance = self.shared.raw.handle();
640
641 let create = unsafe {
646 self.shared
647 .entry
648 .get_instance_proc_addr(raw_instance, c"vkCreateSurfaceOHOS".as_ptr())
649 };
650 let create =
651 unsafe { core::mem::transmute::<vk::PFN_vkVoidFunction, Option<PfnCreateSurfaceOHOS>>(create) };
654 let Some(create) = create else {
655 return Err(crate::InstanceError::new(String::from(
656 "vkCreateSurfaceOHOS not exposed by Vulkan driver",
657 )));
658 };
659
660 let info = VkSurfaceCreateInfoOHOS {
661 s_type: S_TYPE_SURFACE_CREATE_INFO_OHOS,
662 p_next: core::ptr::null(),
663 flags: 0,
664 window,
665 };
666 let mut surface = vk::SurfaceKHR::null();
667 let result = unsafe { create(raw_instance, &info, core::ptr::null(), &mut surface) };
673 if result != vk::Result::SUCCESS {
674 return Err(crate::InstanceError::new(format!(
675 "vkCreateSurfaceOHOS failed: {result:?}"
676 )));
677 }
678
679 Ok(self.create_surface_from_vk_surface_khr(surface, None))
680 }
681
682 fn create_surface_from_hwnd(
683 &self,
684 hinstance: vk::HINSTANCE,
685 hwnd: vk::HWND,
686 ) -> Result<super::Surface, crate::InstanceError> {
687 if !self.shared.extensions.contains(&khr::win32_surface::NAME) {
688 return Err(crate::InstanceError::new(String::from(
689 "Vulkan driver does not support VK_KHR_win32_surface",
690 )));
691 }
692
693 let surface = {
694 let info = vk::Win32SurfaceCreateInfoKHR::default()
695 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
696 .hinstance(hinstance)
697 .hwnd(hwnd);
698 let win32_loader =
699 khr::win32_surface::Instance::new(&self.shared.entry, &self.shared.raw);
700 unsafe { win32_loader.create_win32_surface(&info, None) }
701 }
702 .map_err(|err| {
703 crate::InstanceError::with_source(String::from("Unable to create Win32 surface"), err)
704 })?;
705
706 #[cfg(windows)]
709 let window_handle = Some(crate::vulkan::swapchain::WindowHandle(
710 windows::Win32::Foundation::HWND(hwnd as *mut c_void),
711 ));
712 #[cfg(not(windows))]
713 let window_handle: Option<crate::vulkan::swapchain::WindowHandle> = None;
714 Ok(self.create_surface_from_vk_surface_khr(surface, window_handle))
715 }
716
717 #[cfg(target_vendor = "apple")]
718 fn create_surface_from_layer(
719 &self,
720 layer: raw_window_metal::Layer,
721 ) -> Result<super::Surface, crate::InstanceError> {
722 if !self.shared.extensions.contains(&ext::metal_surface::NAME) {
723 return Err(crate::InstanceError::new(String::from(
724 "Vulkan driver does not support VK_EXT_metal_surface",
725 )));
726 }
727
728 let surface = {
731 let metal_loader =
732 ext::metal_surface::Instance::new(&self.shared.entry, &self.shared.raw);
733 let vk_info = vk::MetalSurfaceCreateInfoEXT::default()
734 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
735 .layer(layer.as_ptr().as_ptr());
736
737 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
738 };
739
740 Ok(self.create_surface_from_vk_surface_khr(surface, None))
741 }
742
743 pub(super) fn create_surface_from_vk_surface_khr(
744 &self,
745 surface: vk::SurfaceKHR,
746 hwnd: Option<crate::vulkan::swapchain::WindowHandle>,
747 ) -> super::Surface {
748 let native_surface =
749 crate::vulkan::swapchain::NativeSurface::from_vk_surface_khr(self, surface, hwnd);
750
751 super::Surface {
752 swapchain: RwLock::new(None),
753 inner: Box::new(native_surface),
754 }
755 }
756
757 pub unsafe fn init_with_callback(
766 desc: &crate::InstanceDescriptor<'_>,
767 callback: Option<Box<super::CreateInstanceCallback>>,
768 ) -> Result<Self, crate::InstanceError> {
769 profiling::scope!("Init Vulkan Backend");
770
771 let entry = unsafe {
772 profiling::scope!("Load vk library");
773 #[cfg(target_env = "ohos")]
776 let loaded = ash::Entry::load_from("libvulkan.so");
777 #[cfg(not(target_env = "ohos"))]
778 let loaded = ash::Entry::load();
779 loaded
780 }
781 .map_err(|err| {
782 crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
783 })?;
784 let version = {
785 profiling::scope!("vkEnumerateInstanceVersion");
786 unsafe { entry.try_enumerate_instance_version() }
787 };
788 let instance_api_version = match version {
789 Ok(Some(version)) => version,
791 Ok(None) => vk::API_VERSION_1_0,
792 Err(err) => {
793 return Err(crate::InstanceError::with_source(
794 String::from("try_enumerate_instance_version() failed"),
795 err,
796 ));
797 }
798 };
799
800 let app_name = CString::new(desc.name).unwrap();
801 let app_info = vk::ApplicationInfo::default()
802 .application_name(app_name.as_c_str())
803 .application_version(1)
804 .engine_name(c"wgpu-hal")
805 .engine_version(2)
806 .api_version(
807 if instance_api_version < vk::API_VERSION_1_1 {
809 vk::API_VERSION_1_0
810 } else {
811 vk::API_VERSION_1_3
820 },
821 );
822
823 let mut extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
824 let mut create_info = vk::InstanceCreateInfo::default();
825
826 if let Some(callback) = callback {
827 callback(super::CreateInstanceCallbackArgs {
828 extensions: &mut extensions,
829 create_info: &mut create_info,
830 entry: &entry,
831 _phantom: PhantomData,
832 });
833 }
834
835 let instance_layers = {
836 profiling::scope!("vkEnumerateInstanceLayerProperties");
837 unsafe { entry.enumerate_instance_layer_properties() }
838 };
839 let instance_layers = instance_layers.map_err(|e| {
840 log::debug!("enumerate_instance_layer_properties: {e:?}");
841 crate::InstanceError::with_source(
842 String::from("enumerate_instance_layer_properties() failed"),
843 e,
844 )
845 })?;
846
847 fn find_layer<'layers>(
848 instance_layers: &'layers [vk::LayerProperties],
849 name: &CStr,
850 ) -> Option<&'layers vk::LayerProperties> {
851 instance_layers
852 .iter()
853 .find(|inst_layer| inst_layer.layer_name_as_c_str() == Ok(name))
854 }
855
856 let validation_layer_name = c"VK_LAYER_KHRONOS_validation";
857 let validation_layer_properties = find_layer(&instance_layers, validation_layer_name);
858
859 let validation_features_are_enabled = if validation_layer_properties.is_some() {
862 let exts =
864 Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?;
865 let mut ext_names = exts
867 .iter()
868 .filter_map(|ext| ext.extension_name_as_c_str().ok());
869 ext_names.any(|ext_name| ext_name == ext::validation_features::NAME)
871 } else {
872 false
873 };
874
875 let should_enable_gpu_based_validation = desc
876 .flags
877 .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
878 && validation_features_are_enabled;
879
880 let should_enable_debug_printf = desc.flags.intersects(wgt::InstanceFlags::DEBUG_PRINTF)
885 && validation_features_are_enabled;
886
887 if desc.flags.intersects(wgt::InstanceFlags::DEBUG_PRINTF) && !should_enable_debug_printf {
888 log::warn!(
889 "InstanceFlags::DEBUG_PRINTF was requested, but shader debug printf output will \
890 not be captured: it requires the validation layers, which are not available."
891 );
892 }
893
894 let has_nv_optimus = find_layer(&instance_layers, c"VK_LAYER_NV_optimus").is_some();
895
896 let has_obs_layer = find_layer(&instance_layers, c"VK_LAYER_OBS_HOOK").is_some();
897
898 let mut layers: Vec<&'static CStr> = Vec::new();
899
900 let has_debug_extension = extensions.contains(&ext::debug_utils::NAME);
901 let mut debug_user_data = has_debug_extension.then(|| {
902 Box::new(super::DebugUtilsMessengerUserData {
905 validation_layer_properties: None,
906 has_obs_layer,
907 })
908 });
909
910 if desc.flags.intersects(wgt::InstanceFlags::VALIDATION)
912 || should_enable_gpu_based_validation
913 {
914 if let Some(layer_properties) = validation_layer_properties {
915 layers.push(validation_layer_name);
916
917 if let Some(debug_user_data) = debug_user_data.as_mut() {
918 debug_user_data.validation_layer_properties =
919 Some(super::ValidationLayerProperties {
920 layer_description: layer_properties
921 .description_as_c_str()
922 .unwrap()
923 .to_owned(),
924 layer_spec_version: layer_properties.spec_version,
925 });
926 }
927 } else {
928 log::debug!(
929 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
930 validation_layer_name.to_string_lossy()
931 );
932 }
933 }
934 let mut debug_utils = if let Some(callback_data) = debug_user_data {
935 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
937 if log::max_level() >= log::LevelFilter::Debug {
938 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
939 }
940 if log::max_level() >= log::LevelFilter::Info {
941 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
942 }
943 if log::max_level() >= log::LevelFilter::Warn {
944 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
945 }
946
947 let message_type = vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
948 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
949 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
950
951 let create_info = super::DebugUtilsCreateInfo {
952 severity,
953 message_type,
954 callback_data,
955 };
956
957 Some(create_info)
958 } else {
959 None
960 };
961
962 #[cfg(target_os = "android")]
963 let android_sdk_version = {
964 let properties = android_system_properties::AndroidSystemProperties::new();
965 if let Some(val) = properties.get("ro.build.version.sdk") {
967 match val.parse::<u32>() {
968 Ok(sdk_ver) => sdk_ver,
969 Err(err) => {
970 log::error!(
971 concat!(
972 "Couldn't parse Android's ",
973 "ro.build.version.sdk system property ({}): {}",
974 ),
975 val,
976 err,
977 );
978 0
979 }
980 }
981 } else {
982 log::error!("Couldn't read Android's ro.build.version.sdk system property");
983 0
984 }
985 };
986 #[cfg(not(target_os = "android"))]
987 let android_sdk_version = 0;
988
989 let mut flags = vk::InstanceCreateFlags::empty();
990
991 if extensions.contains(&khr::portability_enumeration::NAME) {
995 flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
996 }
997 let vk_instance = {
998 let str_pointers = layers
999 .iter()
1000 .chain(extensions.iter())
1001 .map(|&s: &&'static _| {
1002 s.as_ptr()
1004 })
1005 .collect::<Vec<_>>();
1006
1007 create_info = create_info
1008 .flags(flags)
1009 .application_info(&app_info)
1010 .enabled_layer_names(&str_pointers[..layers.len()])
1011 .enabled_extension_names(&str_pointers[layers.len()..]);
1012
1013 let mut debug_utils_create_info = debug_utils
1014 .as_mut()
1015 .map(|create_info| create_info.to_vk_create_info());
1016 if let Some(debug_utils_create_info) = debug_utils_create_info.as_mut() {
1017 create_info = create_info.push_next(debug_utils_create_info);
1018 }
1019
1020 let mut validation_features;
1022 let mut validation_feature_list: ArrayVec<_, 4>;
1023 if validation_features_are_enabled {
1024 validation_feature_list = ArrayVec::new();
1025
1026 validation_feature_list
1028 .push(vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION);
1029
1030 if should_enable_gpu_based_validation {
1032 validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED);
1033 validation_feature_list
1034 .push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT);
1035 }
1036
1037 if should_enable_debug_printf {
1039 validation_feature_list.push(vk::ValidationFeatureEnableEXT::DEBUG_PRINTF);
1040 }
1041
1042 validation_features = vk::ValidationFeaturesEXT::default()
1043 .enabled_validation_features(&validation_feature_list);
1044 create_info = create_info.push_next(&mut validation_features);
1045 }
1046
1047 unsafe {
1048 profiling::scope!("vkCreateInstance");
1049 entry.create_instance(&create_info, None)
1050 }
1051 .map_err(|e| {
1052 crate::InstanceError::with_source(
1053 String::from("Entry::create_instance() failed"),
1054 e,
1055 )
1056 })?
1057 };
1058
1059 unsafe {
1060 Self::from_raw(
1061 entry,
1062 vk_instance,
1063 instance_api_version,
1064 android_sdk_version,
1065 debug_utils,
1066 extensions,
1067 desc.flags,
1068 desc.memory_budget_thresholds,
1069 has_nv_optimus,
1070 None,
1071 )
1072 }
1073 }
1074}
1075
1076impl Drop for super::InstanceShared {
1077 fn drop(&mut self) {
1078 unsafe {
1079 let _du = self.debug_utils.take().inspect(|du| {
1081 du.extension
1082 .destroy_debug_utils_messenger(du.messenger, None);
1083 });
1084 if self.drop_guard.is_none() {
1085 self.raw.destroy_instance(None);
1086 }
1087 }
1088 }
1089}
1090
1091impl crate::Instance for super::Instance {
1092 type A = super::Api;
1093
1094 unsafe fn init(desc: &crate::InstanceDescriptor<'_>) -> Result<Self, crate::InstanceError> {
1095 unsafe { Self::init_with_callback(desc, None) }
1096 }
1097
1098 unsafe fn create_surface(
1099 &self,
1100 display_handle: raw_window_handle::RawDisplayHandle,
1101 window_handle: raw_window_handle::RawWindowHandle,
1102 ) -> Result<super::Surface, crate::InstanceError> {
1103 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
1104
1105 match (window_handle, display_handle) {
1108 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
1109 self.create_surface_from_wayland(display.display.as_ptr(), handle.surface.as_ptr())
1110 }
1111 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
1112 let display = display.display.expect("Display pointer is not set.");
1113 self.create_surface_from_xlib(display.as_ptr(), handle.window)
1114 }
1115 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
1116 let connection = display.connection.expect("Pointer to X-Server is not set.");
1117 self.create_surface_from_xcb(connection.as_ptr(), handle.window.get())
1118 }
1119 #[cfg(drm)]
1120 (Rwh::Drm(handle), Rdh::Drm(display)) => {
1121 self.create_surface_from_drm_plane(display.fd, handle.plane)
1122 }
1123 (Rwh::AndroidNdk(handle), _) => {
1124 self.create_surface_android(handle.a_native_window.as_ptr())
1125 }
1126 #[cfg(target_env = "ohos")]
1127 (Rwh::OhosNdk(handle), _) => self.create_surface_ohos(handle.native_window.as_ptr()),
1128 (Rwh::Win32(handle), _) => {
1129 let hinstance = handle.hinstance.ok_or_else(|| {
1130 crate::InstanceError::new(String::from(
1131 "Vulkan requires raw-window-handle's Win32::hinstance to be set",
1132 ))
1133 })?;
1134 self.create_surface_from_hwnd(hinstance.get(), handle.hwnd.get())
1135 }
1136 #[cfg(target_vendor = "apple")]
1137 (Rwh::AppKit(handle), _)
1138 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
1139 {
1140 let layer = unsafe { raw_window_metal::Layer::from_ns_view(handle.ns_view) };
1141 self.create_surface_from_layer(layer)
1142 }
1143 #[cfg(target_vendor = "apple")]
1144 (Rwh::UiKit(handle), _)
1145 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
1146 {
1147 let layer = unsafe { raw_window_metal::Layer::from_ui_view(handle.ui_view) };
1148 self.create_surface_from_layer(layer)
1149 }
1150 (_, _) => Err(crate::InstanceError::new(format!(
1151 "window handle {window_handle:?} is not a Vulkan-compatible handle"
1152 ))),
1153 }
1154 }
1155
1156 unsafe fn enumerate_adapters(
1157 &self,
1158 _surface_hint: Option<&super::Surface>,
1159 ) -> Vec<crate::ExposedAdapter<super::Api>> {
1160 use crate::auxil::db;
1161
1162 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
1163 Ok(devices) => devices,
1164 Err(err) => {
1165 log::error!("enumerate_adapters: {err}");
1166 Vec::new()
1167 }
1168 };
1169
1170 let mut exposed_adapters = raw_devices
1171 .into_iter()
1172 .flat_map(|device| self.expose_adapter(device))
1173 .collect::<Vec<_>>();
1174
1175 let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| {
1177 exposed.info.device_type == wgt::DeviceType::DiscreteGpu
1178 && exposed.info.vendor == db::nvidia::VENDOR
1179 });
1180 if cfg!(target_os = "linux") && has_nvidia_dgpu && self.shared.has_nv_optimus {
1181 for exposed in exposed_adapters.iter_mut() {
1182 if exposed.info.device_type == wgt::DeviceType::IntegratedGpu
1183 && exposed.info.vendor == db::intel::VENDOR
1184 {
1185 if let Some(version) = exposed.info.driver_info.split_once("Mesa ").map(|s| {
1187 let mut components = s.1.split('.');
1188 let major = components.next().and_then(|s| u8::from_str(s).ok());
1189 let minor = components.next().and_then(|s| u8::from_str(s).ok());
1190 if let (Some(major), Some(minor)) = (major, minor) {
1191 (major, minor)
1192 } else {
1193 (0, 0)
1194 }
1195 }) {
1196 if version < (21, 2) {
1197 log::debug!(
1199 concat!(
1200 "Disabling presentation on '{}' (id {:?}) ",
1201 "due to NV Optimus and Intel Mesa < v21.2"
1202 ),
1203 exposed.info.name,
1204 exposed.adapter.raw
1205 );
1206 exposed.adapter.private_caps.can_present = false;
1207 }
1208 }
1209 }
1210 }
1211 }
1212
1213 exposed_adapters
1214 }
1215}
1216
1217impl crate::Surface for super::Surface {
1218 type A = super::Api;
1219
1220 unsafe fn configure(
1221 &self,
1222 device: &super::Device,
1223 config: &crate::SurfaceConfiguration,
1224 ) -> Result<(), crate::SurfaceError> {
1225 let mut swap_chain = self.swapchain.write();
1227
1228 let mut old = swap_chain.take();
1229 if let Some(ref mut old) = old {
1230 unsafe { old.release_resources(device) };
1231 }
1232
1233 let swapchain = unsafe { self.inner.create_swapchain(device, config, old)? };
1234 *swap_chain = Some(swapchain);
1235
1236 Ok(())
1237 }
1238
1239 unsafe fn unconfigure(&self, device: &super::Device) {
1240 if let Some(mut sc) = self.swapchain.write().take() {
1241 unsafe { sc.release_resources(device) };
1243 }
1244 }
1245
1246 unsafe fn acquire_texture(
1247 &self,
1248 timeout: Option<core::time::Duration>,
1249 fence: &super::Fence,
1250 ) -> Result<crate::AcquiredSurfaceTexture<super::Api>, crate::SurfaceError> {
1251 let mut swapchain = self.swapchain.write();
1252 let swapchain = swapchain.as_mut().unwrap();
1253
1254 unsafe { swapchain.acquire(timeout, fence) }
1255 }
1256
1257 unsafe fn discard_texture(&self, texture: super::SurfaceTexture) {
1258 unsafe {
1259 self.swapchain
1260 .write()
1261 .as_mut()
1262 .unwrap()
1263 .discard_texture(texture)
1264 .unwrap()
1265 };
1266 }
1267}