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