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::Trace,
87 vk::DebugUtilsMessageSeverityFlagsEXT::INFO => log::Level::Debug,
88 vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => log::Level::Warn,
89 vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => log::Level::Error,
90 _ => log::Level::Warn,
91 };
92
93 let message_id_name =
94 unsafe { cd.message_id_name_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
95 let message = unsafe { cd.message_as_c_str() }.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
96
97 let _ = std::panic::catch_unwind(|| {
98 log::log!(
99 level,
100 "{:?} [{} (0x{:x})]\n\t{}",
101 message_type,
102 message_id_name,
103 cd.message_id_number,
104 message,
105 );
106 });
107
108 if cd.queue_label_count != 0 {
109 let labels =
110 unsafe { slice::from_raw_parts(cd.p_queue_labels, cd.queue_label_count as usize) };
111 let names = labels
112 .iter()
113 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
114 .collect::<Vec<_>>();
115
116 let _ = std::panic::catch_unwind(|| {
117 log::log!(level, "\tqueues: {}", names.join(", "));
118 });
119 }
120
121 if cd.cmd_buf_label_count != 0 {
122 let labels =
123 unsafe { slice::from_raw_parts(cd.p_cmd_buf_labels, cd.cmd_buf_label_count as usize) };
124 let names = labels
125 .iter()
126 .flat_map(|dul_obj| unsafe { dul_obj.label_name_as_c_str() }.map(CStr::to_string_lossy))
127 .collect::<Vec<_>>();
128
129 let _ = std::panic::catch_unwind(|| {
130 log::log!(level, "\tcommand buffers: {}", names.join(", "));
131 });
132 }
133
134 if cd.object_count != 0 {
135 let labels = unsafe { slice::from_raw_parts(cd.p_objects, cd.object_count as usize) };
136 let names = labels
138 .iter()
139 .map(|obj_info| {
140 let name = unsafe { obj_info.object_name_as_c_str() }
141 .map_or(Cow::Borrowed("?"), CStr::to_string_lossy);
142
143 format!(
144 "(type: {:?}, hndl: 0x{:x}, name: {})",
145 obj_info.object_type, obj_info.object_handle, name
146 )
147 })
148 .collect::<Vec<_>>();
149 let _ = std::panic::catch_unwind(|| {
150 log::log!(level, "\tobjects: {}", names.join(", "));
151 });
152 }
153
154 #[cfg(feature = "validation_canary")]
155 if cfg!(debug_assertions) && level == log::Level::Error {
156 use alloc::string::ToString as _;
157
158 crate::VALIDATION_CANARY.add(message.to_string());
160 }
161
162 vk::FALSE
163}
164
165impl super::DebugUtilsCreateInfo {
166 fn to_vk_create_info(&self) -> vk::DebugUtilsMessengerCreateInfoEXT<'_> {
167 let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*self.callback_data;
168 vk::DebugUtilsMessengerCreateInfoEXT::default()
169 .message_severity(self.severity)
170 .message_type(self.message_type)
171 .user_data(user_data_ptr as *mut _)
172 .pfn_user_callback(Some(debug_utils_messenger_callback))
173 }
174}
175
176impl super::InstanceShared {
177 pub fn entry(&self) -> &ash::Entry {
178 &self.entry
179 }
180
181 pub fn raw_instance(&self) -> &ash::Instance {
182 &self.raw
183 }
184
185 pub fn instance_api_version(&self) -> u32 {
186 self.instance_api_version
187 }
188
189 pub fn extensions(&self) -> &[&'static CStr] {
190 &self.extensions[..]
191 }
192}
193
194impl super::Instance {
195 pub fn shared_instance(&self) -> &super::InstanceShared {
196 &self.shared
197 }
198
199 fn enumerate_instance_extension_properties(
200 entry: &ash::Entry,
201 layer_name: Option<&CStr>,
202 ) -> Result<Vec<vk::ExtensionProperties>, crate::InstanceError> {
203 let instance_extensions = {
204 profiling::scope!("vkEnumerateInstanceExtensionProperties");
205 unsafe { entry.enumerate_instance_extension_properties(layer_name) }
206 };
207 instance_extensions.map_err(|e| {
208 crate::InstanceError::with_source(
209 String::from("enumerate_instance_extension_properties() failed"),
210 e,
211 )
212 })
213 }
214
215 pub fn desired_extensions(
229 entry: &ash::Entry,
230 _instance_api_version: u32,
231 flags: wgt::InstanceFlags,
232 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
233 let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?;
234
235 let mut extensions: Vec<&'static CStr> = Vec::new();
237
238 extensions.push(khr::surface::NAME);
240
241 if cfg!(all(
243 unix,
244 not(target_os = "android"),
245 not(target_os = "macos")
246 )) {
247 extensions.push(khr::xlib_surface::NAME);
249 extensions.push(khr::xcb_surface::NAME);
251 extensions.push(khr::wayland_surface::NAME);
253 }
254 if cfg!(target_os = "android") {
255 extensions.push(khr::android_surface::NAME);
257 }
258 if cfg!(target_os = "windows") {
259 extensions.push(khr::win32_surface::NAME);
261 }
262 if cfg!(target_os = "macos") {
263 extensions.push(ext::metal_surface::NAME);
265 extensions.push(khr::portability_enumeration::NAME);
266 }
267 if cfg!(drm) {
268 extensions.push(ext::acquire_drm_display::NAME);
270 extensions.push(ext::direct_mode_display::NAME);
271 extensions.push(khr::display::NAME);
272 extensions.push(khr::get_physical_device_properties2::NAME);
273 extensions.push(khr::get_display_properties2::NAME);
274 }
275
276 if flags.contains(wgt::InstanceFlags::DEBUG) {
277 extensions.push(ext::debug_utils::NAME);
279 }
280
281 extensions.push(ext::swapchain_colorspace::NAME);
284
285 extensions.push(khr::get_physical_device_properties2::NAME);
289
290 extensions.retain(|&ext| {
292 if instance_extensions
293 .iter()
294 .any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext))
295 {
296 true
297 } else {
298 log::debug!("Unable to find extension: {}", ext.to_string_lossy());
299 false
300 }
301 });
302 Ok(extensions)
303 }
304
305 #[allow(clippy::too_many_arguments)]
318 pub unsafe fn from_raw(
319 entry: ash::Entry,
320 raw_instance: ash::Instance,
321 instance_api_version: u32,
322 android_sdk_version: u32,
323 debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
324 extensions: Vec<&'static CStr>,
325 flags: wgt::InstanceFlags,
326 memory_budget_thresholds: wgt::MemoryBudgetThresholds,
327 has_nv_optimus: bool,
328 drop_callback: Option<crate::DropCallback>,
329 ) -> Result<Self, crate::InstanceError> {
330 log::debug!("Instance version: 0x{instance_api_version:x}");
331
332 let debug_utils = if let Some(debug_utils_create_info) = debug_utils_create_info {
333 if extensions.contains(&ext::debug_utils::NAME) {
334 log::debug!("Enabling debug utils");
335
336 let extension = ext::debug_utils::Instance::new(&entry, &raw_instance);
337 let vk_info = debug_utils_create_info.to_vk_create_info();
338 let messenger =
339 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
340
341 Some(super::DebugUtils {
342 extension,
343 messenger,
344 callback_data: debug_utils_create_info.callback_data,
345 })
346 } else {
347 log::debug!("Debug utils not enabled: extension not listed");
348 None
349 }
350 } else {
351 log::debug!(
352 "Debug utils not enabled: \
353 debug_utils_user_data not passed to Instance::from_raw"
354 );
355 None
356 };
357
358 let get_physical_device_properties =
359 if extensions.contains(&khr::get_physical_device_properties2::NAME) {
360 log::debug!("Enabling device properties2");
361 Some(khr::get_physical_device_properties2::Instance::new(
362 &entry,
363 &raw_instance,
364 ))
365 } else {
366 None
367 };
368
369 let drop_guard = crate::DropGuard::from_option(drop_callback);
370
371 Ok(Self {
372 shared: Arc::new(super::InstanceShared {
373 raw: raw_instance,
374 extensions,
375 drop_guard,
376 flags,
377 memory_budget_thresholds,
378 debug_utils,
379 get_physical_device_properties,
380 entry,
381 has_nv_optimus,
382 instance_api_version,
383 android_sdk_version,
384 }),
385 })
386 }
387
388 fn create_surface_from_xlib(
389 &self,
390 dpy: *mut vk::Display,
391 window: vk::Window,
392 ) -> Result<super::Surface, crate::InstanceError> {
393 if !self.shared.extensions.contains(&khr::xlib_surface::NAME) {
394 return Err(crate::InstanceError::new(String::from(
395 "Vulkan driver does not support VK_KHR_xlib_surface",
396 )));
397 }
398
399 let surface = {
400 let xlib_loader =
401 khr::xlib_surface::Instance::new(&self.shared.entry, &self.shared.raw);
402 let info = vk::XlibSurfaceCreateInfoKHR::default()
403 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
404 .window(window)
405 .dpy(dpy);
406
407 unsafe { xlib_loader.create_xlib_surface(&info, None) }
408 .expect("XlibSurface::create_xlib_surface() failed")
409 };
410
411 Ok(self.create_surface_from_vk_surface_khr(surface))
412 }
413
414 fn create_surface_from_xcb(
415 &self,
416 connection: *mut vk::xcb_connection_t,
417 window: vk::xcb_window_t,
418 ) -> Result<super::Surface, crate::InstanceError> {
419 if !self.shared.extensions.contains(&khr::xcb_surface::NAME) {
420 return Err(crate::InstanceError::new(String::from(
421 "Vulkan driver does not support VK_KHR_xcb_surface",
422 )));
423 }
424
425 let surface = {
426 let xcb_loader = khr::xcb_surface::Instance::new(&self.shared.entry, &self.shared.raw);
427 let info = vk::XcbSurfaceCreateInfoKHR::default()
428 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
429 .window(window)
430 .connection(connection);
431
432 unsafe { xcb_loader.create_xcb_surface(&info, None) }
433 .expect("XcbSurface::create_xcb_surface() failed")
434 };
435
436 Ok(self.create_surface_from_vk_surface_khr(surface))
437 }
438
439 fn create_surface_from_wayland(
440 &self,
441 display: *mut vk::wl_display,
442 surface: *mut vk::wl_surface,
443 ) -> Result<super::Surface, crate::InstanceError> {
444 if !self.shared.extensions.contains(&khr::wayland_surface::NAME) {
445 return Err(crate::InstanceError::new(String::from(
446 "Vulkan driver does not support VK_KHR_wayland_surface",
447 )));
448 }
449
450 let surface = {
451 let w_loader =
452 khr::wayland_surface::Instance::new(&self.shared.entry, &self.shared.raw);
453 let info = vk::WaylandSurfaceCreateInfoKHR::default()
454 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
455 .display(display)
456 .surface(surface);
457
458 unsafe { w_loader.create_wayland_surface(&info, None) }.expect("WaylandSurface failed")
459 };
460
461 Ok(self.create_surface_from_vk_surface_khr(surface))
462 }
463
464 fn create_surface_android(
465 &self,
466 window: *mut vk::ANativeWindow,
467 ) -> Result<super::Surface, crate::InstanceError> {
468 if !self.shared.extensions.contains(&khr::android_surface::NAME) {
469 return Err(crate::InstanceError::new(String::from(
470 "Vulkan driver does not support VK_KHR_android_surface",
471 )));
472 }
473
474 let surface = {
475 let a_loader =
476 khr::android_surface::Instance::new(&self.shared.entry, &self.shared.raw);
477 let info = vk::AndroidSurfaceCreateInfoKHR::default()
478 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
479 .window(window);
480
481 unsafe { a_loader.create_android_surface(&info, None) }.expect("AndroidSurface failed")
482 };
483
484 Ok(self.create_surface_from_vk_surface_khr(surface))
485 }
486
487 fn create_surface_from_hwnd(
488 &self,
489 hinstance: vk::HINSTANCE,
490 hwnd: vk::HWND,
491 ) -> Result<super::Surface, crate::InstanceError> {
492 if !self.shared.extensions.contains(&khr::win32_surface::NAME) {
493 return Err(crate::InstanceError::new(String::from(
494 "Vulkan driver does not support VK_KHR_win32_surface",
495 )));
496 }
497
498 let surface = {
499 let info = vk::Win32SurfaceCreateInfoKHR::default()
500 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
501 .hinstance(hinstance)
502 .hwnd(hwnd);
503 let win32_loader =
504 khr::win32_surface::Instance::new(&self.shared.entry, &self.shared.raw);
505 unsafe {
506 win32_loader
507 .create_win32_surface(&info, None)
508 .expect("Unable to create Win32 surface")
509 }
510 };
511
512 Ok(self.create_surface_from_vk_surface_khr(surface))
513 }
514
515 #[cfg(target_vendor = "apple")]
516 fn create_surface_from_layer(
517 &self,
518 layer: raw_window_metal::Layer,
519 ) -> Result<super::Surface, crate::InstanceError> {
520 if !self.shared.extensions.contains(&ext::metal_surface::NAME) {
521 return Err(crate::InstanceError::new(String::from(
522 "Vulkan driver does not support VK_EXT_metal_surface",
523 )));
524 }
525
526 let surface = {
529 let metal_loader =
530 ext::metal_surface::Instance::new(&self.shared.entry, &self.shared.raw);
531 let vk_info = vk::MetalSurfaceCreateInfoEXT::default()
532 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
533 .layer(layer.as_ptr().as_ptr());
534
535 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
536 };
537
538 Ok(self.create_surface_from_vk_surface_khr(surface))
539 }
540
541 pub(super) fn create_surface_from_vk_surface_khr(
542 &self,
543 surface: vk::SurfaceKHR,
544 ) -> super::Surface {
545 let native_surface =
546 crate::vulkan::swapchain::NativeSurface::from_vk_surface_khr(self, surface);
547
548 super::Surface {
549 inner: ManuallyDrop::new(Box::new(native_surface)),
550 swapchain: RwLock::new(None),
551 }
552 }
553
554 pub unsafe fn init_with_callback(
563 desc: &crate::InstanceDescriptor<'_>,
564 callback: Option<Box<super::CreateInstanceCallback>>,
565 ) -> Result<Self, crate::InstanceError> {
566 profiling::scope!("Init Vulkan Backend");
567
568 let entry = unsafe {
569 profiling::scope!("Load vk library");
570 ash::Entry::load()
571 }
572 .map_err(|err| {
573 crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
574 })?;
575 let version = {
576 profiling::scope!("vkEnumerateInstanceVersion");
577 unsafe { entry.try_enumerate_instance_version() }
578 };
579 let instance_api_version = match version {
580 Ok(Some(version)) => version,
582 Ok(None) => vk::API_VERSION_1_0,
583 Err(err) => {
584 return Err(crate::InstanceError::with_source(
585 String::from("try_enumerate_instance_version() failed"),
586 err,
587 ));
588 }
589 };
590
591 let app_name = CString::new(desc.name).unwrap();
592 let app_info = vk::ApplicationInfo::default()
593 .application_name(app_name.as_c_str())
594 .application_version(1)
595 .engine_name(c"wgpu-hal")
596 .engine_version(2)
597 .api_version(
598 if instance_api_version < vk::API_VERSION_1_1 {
600 vk::API_VERSION_1_0
601 } else {
602 vk::API_VERSION_1_3
611 },
612 );
613
614 let mut extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
615 let mut create_info = vk::InstanceCreateInfo::default();
616
617 if let Some(callback) = callback {
618 callback(super::CreateInstanceCallbackArgs {
619 extensions: &mut extensions,
620 create_info: &mut create_info,
621 entry: &entry,
622 _phantom: PhantomData,
623 });
624 }
625
626 let instance_layers = {
627 profiling::scope!("vkEnumerateInstanceLayerProperties");
628 unsafe { entry.enumerate_instance_layer_properties() }
629 };
630 let instance_layers = instance_layers.map_err(|e| {
631 log::debug!("enumerate_instance_layer_properties: {e:?}");
632 crate::InstanceError::with_source(
633 String::from("enumerate_instance_layer_properties() failed"),
634 e,
635 )
636 })?;
637
638 fn find_layer<'layers>(
639 instance_layers: &'layers [vk::LayerProperties],
640 name: &CStr,
641 ) -> Option<&'layers vk::LayerProperties> {
642 instance_layers
643 .iter()
644 .find(|inst_layer| inst_layer.layer_name_as_c_str() == Ok(name))
645 }
646
647 let validation_layer_name = c"VK_LAYER_KHRONOS_validation";
648 let validation_layer_properties = find_layer(&instance_layers, validation_layer_name);
649
650 let validation_features_are_enabled = if validation_layer_properties.is_some() {
653 let exts =
655 Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?;
656 let mut ext_names = exts
658 .iter()
659 .filter_map(|ext| ext.extension_name_as_c_str().ok());
660 ext_names.any(|ext_name| ext_name == ext::validation_features::NAME)
662 } else {
663 false
664 };
665
666 let should_enable_gpu_based_validation = desc
667 .flags
668 .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
669 && validation_features_are_enabled;
670
671 let has_nv_optimus = find_layer(&instance_layers, c"VK_LAYER_NV_optimus").is_some();
672
673 let has_obs_layer = find_layer(&instance_layers, c"VK_LAYER_OBS_HOOK").is_some();
674
675 let mut layers: Vec<&'static CStr> = Vec::new();
676
677 let has_debug_extension = extensions.contains(&ext::debug_utils::NAME);
678 let mut debug_user_data = has_debug_extension.then(|| {
679 Box::new(super::DebugUtilsMessengerUserData {
682 validation_layer_properties: None,
683 has_obs_layer,
684 })
685 });
686
687 if desc.flags.intersects(wgt::InstanceFlags::VALIDATION)
689 || should_enable_gpu_based_validation
690 {
691 if let Some(layer_properties) = validation_layer_properties {
692 layers.push(validation_layer_name);
693
694 if let Some(debug_user_data) = debug_user_data.as_mut() {
695 debug_user_data.validation_layer_properties =
696 Some(super::ValidationLayerProperties {
697 layer_description: layer_properties
698 .description_as_c_str()
699 .unwrap()
700 .to_owned(),
701 layer_spec_version: layer_properties.spec_version,
702 });
703 }
704 } else {
705 log::debug!(
706 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
707 validation_layer_name.to_string_lossy()
708 );
709 }
710 }
711 let mut debug_utils = if let Some(callback_data) = debug_user_data {
712 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
714 if log::max_level() >= log::LevelFilter::Debug {
715 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
716 }
717 if log::max_level() >= log::LevelFilter::Info {
718 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
719 }
720 if log::max_level() >= log::LevelFilter::Warn {
721 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
722 }
723
724 let message_type = vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
725 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
726 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
727
728 let create_info = super::DebugUtilsCreateInfo {
729 severity,
730 message_type,
731 callback_data,
732 };
733
734 Some(create_info)
735 } else {
736 None
737 };
738
739 #[cfg(target_os = "android")]
740 let android_sdk_version = {
741 let properties = android_system_properties::AndroidSystemProperties::new();
742 if let Some(val) = properties.get("ro.build.version.sdk") {
744 match val.parse::<u32>() {
745 Ok(sdk_ver) => sdk_ver,
746 Err(err) => {
747 log::error!(
748 concat!(
749 "Couldn't parse Android's ",
750 "ro.build.version.sdk system property ({}): {}",
751 ),
752 val,
753 err,
754 );
755 0
756 }
757 }
758 } else {
759 log::error!("Couldn't read Android's ro.build.version.sdk system property");
760 0
761 }
762 };
763 #[cfg(not(target_os = "android"))]
764 let android_sdk_version = 0;
765
766 let mut flags = vk::InstanceCreateFlags::empty();
767
768 if extensions.contains(&khr::portability_enumeration::NAME) {
772 flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
773 }
774 let vk_instance = {
775 let str_pointers = layers
776 .iter()
777 .chain(extensions.iter())
778 .map(|&s: &&'static _| {
779 s.as_ptr()
781 })
782 .collect::<Vec<_>>();
783
784 create_info = create_info
785 .flags(flags)
786 .application_info(&app_info)
787 .enabled_layer_names(&str_pointers[..layers.len()])
788 .enabled_extension_names(&str_pointers[layers.len()..]);
789
790 let mut debug_utils_create_info = debug_utils
791 .as_mut()
792 .map(|create_info| create_info.to_vk_create_info());
793 if let Some(debug_utils_create_info) = debug_utils_create_info.as_mut() {
794 create_info = create_info.push_next(debug_utils_create_info);
795 }
796
797 let mut validation_features;
799 let mut validation_feature_list: ArrayVec<_, 3>;
800 if validation_features_are_enabled {
801 validation_feature_list = ArrayVec::new();
802
803 validation_feature_list
805 .push(vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION);
806
807 if should_enable_gpu_based_validation {
809 validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED);
810 validation_feature_list
811 .push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT);
812 }
813
814 validation_features = vk::ValidationFeaturesEXT::default()
815 .enabled_validation_features(&validation_feature_list);
816 create_info = create_info.push_next(&mut validation_features);
817 }
818
819 unsafe {
820 profiling::scope!("vkCreateInstance");
821 entry.create_instance(&create_info, None)
822 }
823 .map_err(|e| {
824 crate::InstanceError::with_source(
825 String::from("Entry::create_instance() failed"),
826 e,
827 )
828 })?
829 };
830
831 unsafe {
832 Self::from_raw(
833 entry,
834 vk_instance,
835 instance_api_version,
836 android_sdk_version,
837 debug_utils,
838 extensions,
839 desc.flags,
840 desc.memory_budget_thresholds,
841 has_nv_optimus,
842 None,
843 )
844 }
845 }
846}
847
848impl Drop for super::InstanceShared {
849 fn drop(&mut self) {
850 unsafe {
851 let _du = self.debug_utils.take().inspect(|du| {
853 du.extension
854 .destroy_debug_utils_messenger(du.messenger, None);
855 });
856 if self.drop_guard.is_none() {
857 self.raw.destroy_instance(None);
858 }
859 }
860 }
861}
862
863impl crate::Instance for super::Instance {
864 type A = super::Api;
865
866 unsafe fn init(desc: &crate::InstanceDescriptor<'_>) -> Result<Self, crate::InstanceError> {
867 unsafe { Self::init_with_callback(desc, None) }
868 }
869
870 unsafe fn create_surface(
871 &self,
872 display_handle: raw_window_handle::RawDisplayHandle,
873 window_handle: raw_window_handle::RawWindowHandle,
874 ) -> Result<super::Surface, crate::InstanceError> {
875 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
876
877 match (window_handle, display_handle) {
880 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
881 self.create_surface_from_wayland(display.display.as_ptr(), handle.surface.as_ptr())
882 }
883 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
884 let display = display.display.expect("Display pointer is not set.");
885 self.create_surface_from_xlib(display.as_ptr(), handle.window)
886 }
887 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
888 let connection = display.connection.expect("Pointer to X-Server is not set.");
889 self.create_surface_from_xcb(connection.as_ptr(), handle.window.get())
890 }
891 #[cfg(drm)]
892 (Rwh::Drm(handle), Rdh::Drm(display)) => {
893 self.create_surface_from_drm_plane(display.fd, handle.plane)
894 }
895 (Rwh::AndroidNdk(handle), _) => {
896 self.create_surface_android(handle.a_native_window.as_ptr())
897 }
898 (Rwh::Win32(handle), _) => {
899 let hinstance = handle.hinstance.ok_or_else(|| {
900 crate::InstanceError::new(String::from(
901 "Vulkan requires raw-window-handle's Win32::hinstance to be set",
902 ))
903 })?;
904 self.create_surface_from_hwnd(hinstance.get(), handle.hwnd.get())
905 }
906 #[cfg(target_vendor = "apple")]
907 (Rwh::AppKit(handle), _)
908 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
909 {
910 let layer = unsafe { raw_window_metal::Layer::from_ns_view(handle.ns_view) };
911 self.create_surface_from_layer(layer)
912 }
913 #[cfg(target_vendor = "apple")]
914 (Rwh::UiKit(handle), _)
915 if self.shared.extensions.contains(&ext::metal_surface::NAME) =>
916 {
917 let layer = unsafe { raw_window_metal::Layer::from_ui_view(handle.ui_view) };
918 self.create_surface_from_layer(layer)
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::debug!(
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<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}