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