1use std::{
2 ffi::{c_void, CStr, CString},
3 slice,
4 str::FromStr,
5 sync::Arc,
6 thread,
7};
8
9use arrayvec::ArrayVec;
10use ash::{
11 extensions::{ext, khr},
12 vk,
13};
14use parking_lot::RwLock;
15
16unsafe extern "system" fn debug_utils_messenger_callback(
17 message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
18 message_type: vk::DebugUtilsMessageTypeFlagsEXT,
19 callback_data_ptr: *const vk::DebugUtilsMessengerCallbackDataEXT,
20 user_data: *mut c_void,
21) -> vk::Bool32 {
22 use std::borrow::Cow;
23
24 if thread::panicking() {
25 return vk::FALSE;
26 }
27
28 let cd = unsafe { &*callback_data_ptr };
29 let user_data = unsafe { &*(user_data as *mut super::DebugUtilsMessengerUserData) };
30
31 const VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912: i32 = 0x56146426;
32 if cd.message_id_number == VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912 {
33 let khronos_validation_layer =
37 std::ffi::CStr::from_bytes_with_nul(b"Khronos Validation Layer\0").unwrap();
38 if let Some(layer_properties) = user_data.validation_layer_properties.as_ref() {
39 if layer_properties.layer_description.as_ref() == 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 let level = match message_severity {
70 vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => log::Level::Debug,
71 vk::DebugUtilsMessageSeverityFlagsEXT::INFO => log::Level::Info,
72 vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => log::Level::Warn,
73 vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => log::Level::Error,
74 _ => log::Level::Warn,
75 };
76
77 let message_id_name = if cd.p_message_id_name.is_null() {
78 Cow::from("")
79 } else {
80 unsafe { CStr::from_ptr(cd.p_message_id_name) }.to_string_lossy()
81 };
82 let message = if cd.p_message.is_null() {
83 Cow::from("")
84 } else {
85 unsafe { CStr::from_ptr(cd.p_message) }.to_string_lossy()
86 };
87
88 let _ = std::panic::catch_unwind(|| {
89 log::log!(
90 level,
91 "{:?} [{} (0x{:x})]\n\t{}",
92 message_type,
93 message_id_name,
94 cd.message_id_number,
95 message,
96 );
97 });
98
99 if cd.queue_label_count != 0 {
100 let labels =
101 unsafe { slice::from_raw_parts(cd.p_queue_labels, cd.queue_label_count as usize) };
102 let names = labels
103 .iter()
104 .flat_map(|dul_obj| {
105 unsafe { dul_obj.p_label_name.as_ref() }
106 .map(|lbl| unsafe { CStr::from_ptr(lbl) }.to_string_lossy())
107 })
108 .collect::<Vec<_>>();
109
110 let _ = std::panic::catch_unwind(|| {
111 log::log!(level, "\tqueues: {}", names.join(", "));
112 });
113 }
114
115 if cd.cmd_buf_label_count != 0 {
116 let labels =
117 unsafe { slice::from_raw_parts(cd.p_cmd_buf_labels, cd.cmd_buf_label_count as usize) };
118 let names = labels
119 .iter()
120 .flat_map(|dul_obj| {
121 unsafe { dul_obj.p_label_name.as_ref() }
122 .map(|lbl| unsafe { CStr::from_ptr(lbl) }.to_string_lossy())
123 })
124 .collect::<Vec<_>>();
125
126 let _ = std::panic::catch_unwind(|| {
127 log::log!(level, "\tcommand buffers: {}", names.join(", "));
128 });
129 }
130
131 if cd.object_count != 0 {
132 let labels = unsafe { slice::from_raw_parts(cd.p_objects, cd.object_count as usize) };
133 let names = labels
135 .iter()
136 .map(|obj_info| {
137 let name = unsafe { obj_info.p_object_name.as_ref() }
138 .map(|name| unsafe { CStr::from_ptr(name) }.to_string_lossy())
139 .unwrap_or(Cow::Borrowed("?"));
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 if cfg!(debug_assertions) && level == log::Level::Error {
153 crate::VALIDATION_CANARY.add(message.to_string());
155 }
156
157 vk::FALSE
158}
159
160impl super::DebugUtilsCreateInfo {
161 fn to_vk_create_info(&self) -> vk::DebugUtilsMessengerCreateInfoEXTBuilder<'_> {
162 let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*self.callback_data;
163 vk::DebugUtilsMessengerCreateInfoEXT::builder()
164 .message_severity(self.severity)
165 .message_type(self.message_type)
166 .user_data(user_data_ptr as *mut _)
167 .pfn_user_callback(Some(debug_utils_messenger_callback))
168 }
169}
170
171impl super::Swapchain {
172 unsafe fn release_resources(mut self, device: &ash::Device) -> Self {
176 profiling::scope!("Swapchain::release_resources");
177 {
178 profiling::scope!("vkDeviceWaitIdle");
179 let _ = unsafe { device.device_wait_idle() };
182 };
183
184 for semaphore in self.surface_semaphores.drain(..) {
186 let arc_removed = Arc::into_inner(semaphore).expect(
187 "Trying to destroy a SurfaceSemaphores that is still in use by a SurfaceTexture",
188 );
189 let mutex_removed = arc_removed.into_inner();
190
191 unsafe { mutex_removed.destroy(device) };
192 }
193
194 self
195 }
196}
197
198impl super::InstanceShared {
199 pub fn entry(&self) -> &ash::Entry {
200 &self.entry
201 }
202
203 pub fn raw_instance(&self) -> &ash::Instance {
204 &self.raw
205 }
206
207 pub fn instance_api_version(&self) -> u32 {
208 self.instance_api_version
209 }
210
211 pub fn extensions(&self) -> &[&'static CStr] {
212 &self.extensions[..]
213 }
214}
215
216impl super::Instance {
217 pub fn shared_instance(&self) -> &super::InstanceShared {
218 &self.shared
219 }
220
221 fn enumerate_instance_extension_properties(
222 entry: &ash::Entry,
223 layer_name: Option<&CStr>,
224 ) -> Result<Vec<vk::ExtensionProperties>, crate::InstanceError> {
225 let instance_extensions = {
226 profiling::scope!("vkEnumerateInstanceExtensionProperties");
227 entry.enumerate_instance_extension_properties(layer_name)
228 };
229 instance_extensions.map_err(|e| {
230 crate::InstanceError::with_source(
231 String::from("enumerate_instance_extension_properties() failed"),
232 e,
233 )
234 })
235 }
236
237 pub fn desired_extensions(
251 entry: &ash::Entry,
252 _instance_api_version: u32,
253 flags: wgt::InstanceFlags,
254 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
255 let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?;
256
257 let mut extensions: Vec<&'static CStr> = Vec::new();
259
260 extensions.push(khr::Surface::name());
262
263 if cfg!(all(
265 unix,
266 not(target_os = "android"),
267 not(target_os = "macos")
268 )) {
269 extensions.push(khr::XlibSurface::name());
271 extensions.push(khr::XcbSurface::name());
273 extensions.push(khr::WaylandSurface::name());
275 }
276 if cfg!(target_os = "android") {
277 extensions.push(khr::AndroidSurface::name());
279 }
280 if cfg!(target_os = "windows") {
281 extensions.push(khr::Win32Surface::name());
283 }
284 if cfg!(target_os = "macos") {
285 extensions.push(ext::MetalSurface::name());
287 extensions.push(ash::vk::KhrPortabilityEnumerationFn::name());
288 }
289
290 if flags.contains(wgt::InstanceFlags::DEBUG) {
291 extensions.push(ext::DebugUtils::name());
293 }
294
295 extensions.push(vk::ExtSwapchainColorspaceFn::name());
298
299 extensions.push(vk::KhrGetPhysicalDeviceProperties2Fn::name());
303
304 extensions.retain(|&ext| {
306 if instance_extensions.iter().any(|inst_ext| {
307 crate::auxil::cstr_from_bytes_until_nul(&inst_ext.extension_name) == Some(ext)
308 }) {
309 true
310 } else {
311 log::warn!("Unable to find extension: {}", ext.to_string_lossy());
312 false
313 }
314 });
315 Ok(extensions)
316 }
317
318 #[allow(clippy::too_many_arguments)]
329 pub unsafe fn from_raw(
330 entry: ash::Entry,
331 raw_instance: ash::Instance,
332 instance_api_version: u32,
333 android_sdk_version: u32,
334 debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
335 extensions: Vec<&'static CStr>,
336 flags: wgt::InstanceFlags,
337 has_nv_optimus: bool,
338 drop_guard: Option<crate::DropGuard>,
339 ) -> Result<Self, crate::InstanceError> {
340 log::debug!("Instance version: 0x{:x}", instance_api_version);
341
342 let debug_utils = if let Some(debug_utils_create_info) = debug_utils_create_info {
343 if extensions.contains(&ext::DebugUtils::name()) {
344 log::info!("Enabling debug utils");
345
346 let extension = ext::DebugUtils::new(&entry, &raw_instance);
347 let vk_info = debug_utils_create_info.to_vk_create_info();
348 let messenger =
349 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
350
351 Some(super::DebugUtils {
352 extension,
353 messenger,
354 callback_data: debug_utils_create_info.callback_data,
355 })
356 } else {
357 log::info!("Debug utils not enabled: extension not listed");
358 None
359 }
360 } else {
361 log::info!(
362 "Debug utils not enabled: \
363 debug_utils_user_data not passed to Instance::from_raw"
364 );
365 None
366 };
367
368 let get_physical_device_properties =
369 if extensions.contains(&khr::GetPhysicalDeviceProperties2::name()) {
370 log::debug!("Enabling device properties2");
371 Some(khr::GetPhysicalDeviceProperties2::new(
372 &entry,
373 &raw_instance,
374 ))
375 } else {
376 None
377 };
378
379 Ok(Self {
380 shared: Arc::new(super::InstanceShared {
381 raw: raw_instance,
382 extensions,
383 drop_guard,
384 flags,
385 debug_utils,
386 get_physical_device_properties,
387 entry,
388 has_nv_optimus,
389 instance_api_version,
390 android_sdk_version,
391 }),
392 })
393 }
394
395 #[allow(dead_code)]
396 fn create_surface_from_xlib(
397 &self,
398 dpy: *mut vk::Display,
399 window: vk::Window,
400 ) -> Result<super::Surface, crate::InstanceError> {
401 if !self.shared.extensions.contains(&khr::XlibSurface::name()) {
402 return Err(crate::InstanceError::new(String::from(
403 "Vulkan driver does not support VK_KHR_xlib_surface",
404 )));
405 }
406
407 let surface = {
408 let xlib_loader = khr::XlibSurface::new(&self.shared.entry, &self.shared.raw);
409 let info = vk::XlibSurfaceCreateInfoKHR::builder()
410 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
411 .window(window)
412 .dpy(dpy);
413
414 unsafe { xlib_loader.create_xlib_surface(&info, None) }
415 .expect("XlibSurface::create_xlib_surface() failed")
416 };
417
418 Ok(self.create_surface_from_vk_surface_khr(surface))
419 }
420
421 #[allow(dead_code)]
422 fn create_surface_from_xcb(
423 &self,
424 connection: *mut vk::xcb_connection_t,
425 window: vk::xcb_window_t,
426 ) -> Result<super::Surface, crate::InstanceError> {
427 if !self.shared.extensions.contains(&khr::XcbSurface::name()) {
428 return Err(crate::InstanceError::new(String::from(
429 "Vulkan driver does not support VK_KHR_xcb_surface",
430 )));
431 }
432
433 let surface = {
434 let xcb_loader = khr::XcbSurface::new(&self.shared.entry, &self.shared.raw);
435 let info = vk::XcbSurfaceCreateInfoKHR::builder()
436 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
437 .window(window)
438 .connection(connection);
439
440 unsafe { xcb_loader.create_xcb_surface(&info, None) }
441 .expect("XcbSurface::create_xcb_surface() failed")
442 };
443
444 Ok(self.create_surface_from_vk_surface_khr(surface))
445 }
446
447 #[allow(dead_code)]
448 fn create_surface_from_wayland(
449 &self,
450 display: *mut c_void,
451 surface: *mut c_void,
452 ) -> Result<super::Surface, crate::InstanceError> {
453 if !self
454 .shared
455 .extensions
456 .contains(&khr::WaylandSurface::name())
457 {
458 return Err(crate::InstanceError::new(String::from(
459 "Vulkan driver does not support VK_KHR_wayland_surface",
460 )));
461 }
462
463 let surface = {
464 let w_loader = khr::WaylandSurface::new(&self.shared.entry, &self.shared.raw);
465 let info = vk::WaylandSurfaceCreateInfoKHR::builder()
466 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
467 .display(display)
468 .surface(surface);
469
470 unsafe { w_loader.create_wayland_surface(&info, None) }.expect("WaylandSurface failed")
471 };
472
473 Ok(self.create_surface_from_vk_surface_khr(surface))
474 }
475
476 #[allow(dead_code)]
477 fn create_surface_android(
478 &self,
479 window: *const c_void,
480 ) -> Result<super::Surface, crate::InstanceError> {
481 if !self
482 .shared
483 .extensions
484 .contains(&khr::AndroidSurface::name())
485 {
486 return Err(crate::InstanceError::new(String::from(
487 "Vulkan driver does not support VK_KHR_android_surface",
488 )));
489 }
490
491 let surface = {
492 let a_loader = khr::AndroidSurface::new(&self.shared.entry, &self.shared.raw);
493 let info = vk::AndroidSurfaceCreateInfoKHR::builder()
494 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
495 .window(window as *mut _);
496
497 unsafe { a_loader.create_android_surface(&info, None) }.expect("AndroidSurface failed")
498 };
499
500 Ok(self.create_surface_from_vk_surface_khr(surface))
501 }
502
503 #[allow(dead_code)]
504 fn create_surface_from_hwnd(
505 &self,
506 hinstance: *mut c_void,
507 hwnd: *mut c_void,
508 ) -> Result<super::Surface, crate::InstanceError> {
509 if !self.shared.extensions.contains(&khr::Win32Surface::name()) {
510 return Err(crate::InstanceError::new(String::from(
511 "Vulkan driver does not support VK_KHR_win32_surface",
512 )));
513 }
514
515 let surface = {
516 let info = vk::Win32SurfaceCreateInfoKHR::builder()
517 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
518 .hinstance(hinstance)
519 .hwnd(hwnd);
520 let win32_loader = khr::Win32Surface::new(&self.shared.entry, &self.shared.raw);
521 unsafe {
522 win32_loader
523 .create_win32_surface(&info, None)
524 .expect("Unable to create Win32 surface")
525 }
526 };
527
528 Ok(self.create_surface_from_vk_surface_khr(surface))
529 }
530
531 #[cfg(metal)]
532 fn create_surface_from_view(
533 &self,
534 view: *mut c_void,
535 ) -> Result<super::Surface, crate::InstanceError> {
536 if !self.shared.extensions.contains(&ext::MetalSurface::name()) {
537 return Err(crate::InstanceError::new(String::from(
538 "Vulkan driver does not support VK_EXT_metal_surface",
539 )));
540 }
541
542 let layer = unsafe {
543 crate::metal::Surface::get_metal_layer(view as *mut objc::runtime::Object, None)
544 };
545
546 let surface = {
547 let metal_loader = ext::MetalSurface::new(&self.shared.entry, &self.shared.raw);
548 let vk_info = vk::MetalSurfaceCreateInfoEXT::builder()
549 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
550 .layer(layer as *mut _)
551 .build();
552
553 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
554 };
555
556 Ok(self.create_surface_from_vk_surface_khr(surface))
557 }
558
559 fn create_surface_from_vk_surface_khr(&self, surface: vk::SurfaceKHR) -> super::Surface {
560 let functor = khr::Surface::new(&self.shared.entry, &self.shared.raw);
561 super::Surface {
562 raw: surface,
563 functor,
564 instance: Arc::clone(&self.shared),
565 swapchain: RwLock::new(None),
566 }
567 }
568}
569
570impl Drop for super::InstanceShared {
571 fn drop(&mut self) {
572 unsafe {
573 let _du = self.debug_utils.take().map(|du| {
575 du.extension
576 .destroy_debug_utils_messenger(du.messenger, None);
577 du
578 });
579 if let Some(_drop_guard) = self.drop_guard.take() {
580 self.raw.destroy_instance(None);
581 }
582 }
583 }
584}
585
586impl crate::Instance for super::Instance {
587 type A = super::Api;
588
589 unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
590 profiling::scope!("Init Vulkan Backend");
591 use crate::auxil::cstr_from_bytes_until_nul;
592
593 let entry = unsafe {
594 profiling::scope!("Load vk library");
595 ash::Entry::load()
596 }
597 .map_err(|err| {
598 crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
599 })?;
600 let version = {
601 profiling::scope!("vkEnumerateInstanceVersion");
602 entry.try_enumerate_instance_version()
603 };
604 let instance_api_version = match version {
605 Ok(Some(version)) => version,
607 Ok(None) => vk::API_VERSION_1_0,
608 Err(err) => {
609 return Err(crate::InstanceError::with_source(
610 String::from("try_enumerate_instance_version() failed"),
611 err,
612 ));
613 }
614 };
615
616 let app_name = CString::new(desc.name).unwrap();
617 let app_info = vk::ApplicationInfo::builder()
618 .application_name(app_name.as_c_str())
619 .application_version(1)
620 .engine_name(CStr::from_bytes_with_nul(b"wgpu-hal\0").unwrap())
621 .engine_version(2)
622 .api_version(
623 if instance_api_version < vk::API_VERSION_1_1 {
625 vk::API_VERSION_1_0
626 } else {
627 vk::API_VERSION_1_3
636 },
637 );
638
639 let extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
640
641 let instance_layers = {
642 profiling::scope!("vkEnumerateInstanceLayerProperties");
643 entry.enumerate_instance_layer_properties()
644 };
645 let instance_layers = instance_layers.map_err(|e| {
646 log::debug!("enumerate_instance_layer_properties: {:?}", e);
647 crate::InstanceError::with_source(
648 String::from("enumerate_instance_layer_properties() failed"),
649 e,
650 )
651 })?;
652
653 fn find_layer<'layers>(
654 instance_layers: &'layers [vk::LayerProperties],
655 name: &CStr,
656 ) -> Option<&'layers vk::LayerProperties> {
657 instance_layers
658 .iter()
659 .find(|inst_layer| cstr_from_bytes_until_nul(&inst_layer.layer_name) == Some(name))
660 }
661
662 let validation_layer_name =
663 CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap();
664 let validation_layer_properties = find_layer(&instance_layers, validation_layer_name);
665
666 let validation_features_are_enabled = if validation_layer_properties.is_some() {
669 let exts =
671 Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?;
672 let mut ext_names = exts
674 .iter()
675 .filter_map(|ext| cstr_from_bytes_until_nul(&ext.extension_name));
676 ext_names.any(|ext_name| ext_name == vk::ExtValidationFeaturesFn::name())
678 } else {
679 false
680 };
681
682 let should_enable_gpu_based_validation = desc
683 .flags
684 .intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
685 && validation_features_are_enabled;
686
687 let nv_optimus_layer = CStr::from_bytes_with_nul(b"VK_LAYER_NV_optimus\0").unwrap();
688 let has_nv_optimus = find_layer(&instance_layers, nv_optimus_layer).is_some();
689
690 let obs_layer = CStr::from_bytes_with_nul(b"VK_LAYER_OBS_HOOK\0").unwrap();
691 let has_obs_layer = find_layer(&instance_layers, obs_layer).is_some();
692
693 let mut layers: Vec<&'static CStr> = Vec::new();
694
695 let has_debug_extension = extensions.contains(&ext::DebugUtils::name());
696 let mut debug_user_data = has_debug_extension.then(|| {
697 Box::new(super::DebugUtilsMessengerUserData {
700 validation_layer_properties: None,
701 has_obs_layer,
702 })
703 });
704
705 if desc.flags.intersects(wgt::InstanceFlags::VALIDATION)
707 || should_enable_gpu_based_validation
708 {
709 if let Some(layer_properties) = validation_layer_properties {
710 layers.push(validation_layer_name);
711
712 if let Some(debug_user_data) = debug_user_data.as_mut() {
713 debug_user_data.validation_layer_properties =
714 Some(super::ValidationLayerProperties {
715 layer_description: cstr_from_bytes_until_nul(
716 &layer_properties.description,
717 )
718 .unwrap()
719 .to_owned(),
720 layer_spec_version: layer_properties.spec_version,
721 });
722 }
723 } else {
724 log::warn!(
725 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
726 validation_layer_name.to_string_lossy()
727 );
728 }
729 }
730 let mut debug_utils = if let Some(callback_data) = debug_user_data {
731 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
733 if log::max_level() >= log::LevelFilter::Debug {
734 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
735 }
736 if log::max_level() >= log::LevelFilter::Info {
737 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
738 }
739 if log::max_level() >= log::LevelFilter::Warn {
740 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
741 }
742
743 let message_type = vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
744 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
745 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
746
747 let create_info = super::DebugUtilsCreateInfo {
748 severity,
749 message_type,
750 callback_data,
751 };
752
753 let vk_create_info = create_info.to_vk_create_info().build();
754
755 Some((create_info, vk_create_info))
756 } else {
757 None
758 };
759
760 #[cfg(target_os = "android")]
761 let android_sdk_version = {
762 let properties = android_system_properties::AndroidSystemProperties::new();
763 if let Some(val) = properties.get("ro.build.version.sdk") {
765 match val.parse::<u32>() {
766 Ok(sdk_ver) => sdk_ver,
767 Err(err) => {
768 log::error!(
769 "Couldn't parse Android's ro.build.version.sdk system property ({val}): {err}"
770 );
771 0
772 }
773 }
774 } else {
775 log::error!("Couldn't read Android's ro.build.version.sdk system property");
776 0
777 }
778 };
779 #[cfg(not(target_os = "android"))]
780 let android_sdk_version = 0;
781
782 let mut flags = vk::InstanceCreateFlags::empty();
783
784 if extensions.contains(&ash::vk::KhrPortabilityEnumerationFn::name()) {
788 flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
789 }
790 let vk_instance = {
791 let str_pointers = layers
792 .iter()
793 .chain(extensions.iter())
794 .map(|&s: &&'static _| {
795 s.as_ptr()
797 })
798 .collect::<Vec<_>>();
799
800 let mut create_info = vk::InstanceCreateInfo::builder()
801 .flags(flags)
802 .application_info(&app_info)
803 .enabled_layer_names(&str_pointers[..layers.len()])
804 .enabled_extension_names(&str_pointers[layers.len()..]);
805
806 if let Some(&mut (_, ref mut vk_create_info)) = debug_utils.as_mut() {
807 create_info = create_info.push_next(vk_create_info);
808 }
809
810 let mut validation_features;
812 let mut validation_feature_list: ArrayVec<_, 3>;
813 if validation_features_are_enabled {
814 validation_feature_list = ArrayVec::new();
815
816 validation_feature_list
818 .push(vk::ValidationFeatureEnableEXT::SYNCHRONIZATION_VALIDATION);
819
820 if should_enable_gpu_based_validation {
822 validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED);
823 validation_feature_list
824 .push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT);
825 }
826
827 validation_features = vk::ValidationFeaturesEXT::builder()
828 .enabled_validation_features(&validation_feature_list);
829 create_info = create_info.push_next(&mut validation_features);
830 }
831
832 unsafe {
833 profiling::scope!("vkCreateInstance");
834 entry.create_instance(&create_info, None)
835 }
836 .map_err(|e| {
837 crate::InstanceError::with_source(
838 String::from("Entry::create_instance() failed"),
839 e,
840 )
841 })?
842 };
843
844 unsafe {
845 Self::from_raw(
846 entry,
847 vk_instance,
848 instance_api_version,
849 android_sdk_version,
850 debug_utils.map(|(i, _)| i),
851 extensions,
852 desc.flags,
853 has_nv_optimus,
854 Some(Box::new(())), )
856 }
857 }
858
859 unsafe fn create_surface(
860 &self,
861 display_handle: raw_window_handle::RawDisplayHandle,
862 window_handle: raw_window_handle::RawWindowHandle,
863 ) -> Result<super::Surface, crate::InstanceError> {
864 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
865
866 match (window_handle, display_handle) {
867 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
868 self.create_surface_from_wayland(display.display.as_ptr(), handle.surface.as_ptr())
869 }
870 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
871 let display = display.display.expect("Display pointer is not set.");
872 self.create_surface_from_xlib(display.as_ptr() as *mut *const c_void, handle.window)
873 }
874 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
875 let connection = display.connection.expect("Pointer to X-Server is not set.");
876 self.create_surface_from_xcb(connection.as_ptr(), handle.window.get())
877 }
878 (Rwh::AndroidNdk(handle), _) => {
879 self.create_surface_android(handle.a_native_window.as_ptr())
880 }
881 #[cfg(windows)]
882 (Rwh::Win32(handle), _) => {
883 use winapi::um::libloaderapi::GetModuleHandleW;
884
885 let hinstance = unsafe { GetModuleHandleW(std::ptr::null()) };
886 self.create_surface_from_hwnd(hinstance as *mut _, handle.hwnd.get() as *mut _)
887 }
888 #[cfg(all(target_os = "macos", feature = "metal"))]
889 (Rwh::AppKit(handle), _)
890 if self.shared.extensions.contains(&ext::MetalSurface::name()) =>
891 {
892 self.create_surface_from_view(handle.ns_view.as_ptr())
893 }
894 #[cfg(all(target_os = "ios", feature = "metal"))]
895 (Rwh::UiKit(handle), _)
896 if self.shared.extensions.contains(&ext::MetalSurface::name()) =>
897 {
898 self.create_surface_from_view(handle.ui_view.as_ptr())
899 }
900 (_, _) => Err(crate::InstanceError::new(format!(
901 "window handle {window_handle:?} is not a Vulkan-compatible handle"
902 ))),
903 }
904 }
905
906 unsafe fn destroy_surface(&self, surface: super::Surface) {
907 unsafe { surface.functor.destroy_surface(surface.raw, None) };
908 }
909
910 unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
911 use crate::auxil::db;
912
913 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
914 Ok(devices) => devices,
915 Err(err) => {
916 log::error!("enumerate_adapters: {}", err);
917 Vec::new()
918 }
919 };
920
921 let mut exposed_adapters = raw_devices
922 .into_iter()
923 .flat_map(|device| self.expose_adapter(device))
924 .collect::<Vec<_>>();
925
926 let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| {
928 exposed.info.device_type == wgt::DeviceType::DiscreteGpu
929 && exposed.info.vendor == db::nvidia::VENDOR
930 });
931 if cfg!(target_os = "linux") && has_nvidia_dgpu && self.shared.has_nv_optimus {
932 for exposed in exposed_adapters.iter_mut() {
933 if exposed.info.device_type == wgt::DeviceType::IntegratedGpu
934 && exposed.info.vendor == db::intel::VENDOR
935 {
936 if let Some(version) = exposed.info.driver_info.split_once("Mesa ").map(|s| {
938 let mut components = s.1.split('.');
939 let major = components.next().and_then(|s| u8::from_str(s).ok());
940 let minor = components.next().and_then(|s| u8::from_str(s).ok());
941 if let (Some(major), Some(minor)) = (major, minor) {
942 (major, minor)
943 } else {
944 (0, 0)
945 }
946 }) {
947 if version < (21, 2) {
948 log::warn!(
950 "Disabling presentation on '{}' (id {:?}) due to NV Optimus and Intel Mesa < v21.2",
951 exposed.info.name,
952 exposed.adapter.raw
953 );
954 exposed.adapter.private_caps.can_present = false;
955 }
956 }
957 }
958 }
959 }
960
961 exposed_adapters
962 }
963}
964
965impl crate::Surface for super::Surface {
966 type A = super::Api;
967
968 unsafe fn configure(
969 &self,
970 device: &super::Device,
971 config: &crate::SurfaceConfiguration,
972 ) -> Result<(), crate::SurfaceError> {
973 let mut swap_chain = self.swapchain.write();
975 let old = swap_chain
976 .take()
977 .map(|sc| unsafe { sc.release_resources(&device.shared.raw) });
978
979 let swapchain = unsafe { device.create_swapchain(self, config, old)? };
980 *swap_chain = Some(swapchain);
981
982 Ok(())
983 }
984
985 unsafe fn unconfigure(&self, device: &super::Device) {
986 if let Some(sc) = self.swapchain.write().take() {
987 let swapchain = unsafe { sc.release_resources(&device.shared.raw) };
989 unsafe { swapchain.functor.destroy_swapchain(swapchain.raw, None) };
990 }
991 }
992
993 unsafe fn acquire_texture(
994 &self,
995 timeout: Option<std::time::Duration>,
996 fence: &super::Fence,
997 ) -> Result<Option<crate::AcquiredSurfaceTexture<super::Api>>, crate::SurfaceError> {
998 let mut swapchain = self.swapchain.write();
999 let swapchain = swapchain.as_mut().unwrap();
1000
1001 let mut timeout_ns = match timeout {
1002 Some(duration) => duration.as_nanos() as u64,
1003 None => u64::MAX,
1004 };
1005
1006 if cfg!(target_os = "android") && self.instance.android_sdk_version < 30 {
1016 timeout_ns = u64::MAX;
1017 }
1018
1019 let swapchain_semaphores_arc = swapchain.get_surface_semaphores();
1020 let locked_swapchain_semaphores = swapchain_semaphores_arc
1022 .try_lock()
1023 .expect("Failed to lock a SwapchainSemaphores.");
1024
1025 swapchain.device.wait_for_fence(
1039 fence,
1040 locked_swapchain_semaphores.previously_used_submission_index,
1041 timeout_ns,
1042 )?;
1043
1044 let (index, suboptimal) = match unsafe {
1046 profiling::scope!("vkAcquireNextImageKHR");
1047 swapchain.functor.acquire_next_image(
1048 swapchain.raw,
1049 timeout_ns,
1050 locked_swapchain_semaphores.acquire,
1051 vk::Fence::null(),
1052 )
1053 } {
1054 #[cfg(target_os = "android")]
1057 Ok((index, _)) => (index, false),
1058 #[cfg(not(target_os = "android"))]
1059 Ok(pair) => pair,
1060 Err(error) => {
1061 return match error {
1062 vk::Result::TIMEOUT => Ok(None),
1063 vk::Result::NOT_READY | vk::Result::ERROR_OUT_OF_DATE_KHR => {
1064 Err(crate::SurfaceError::Outdated)
1065 }
1066 vk::Result::ERROR_SURFACE_LOST_KHR => Err(crate::SurfaceError::Lost),
1067 other => Err(crate::DeviceError::from(other).into()),
1068 }
1069 }
1070 };
1071
1072 drop(locked_swapchain_semaphores);
1073 swapchain.advance_surface_semaphores();
1076
1077 if swapchain.device.vendor_id == crate::auxil::db::intel::VENDOR && index > 0x100 {
1079 return Err(crate::SurfaceError::Outdated);
1080 }
1081
1082 let raw_flags = if swapchain
1084 .raw_flags
1085 .contains(vk::SwapchainCreateFlagsKHR::MUTABLE_FORMAT)
1086 {
1087 vk::ImageCreateFlags::MUTABLE_FORMAT | vk::ImageCreateFlags::EXTENDED_USAGE
1088 } else {
1089 vk::ImageCreateFlags::empty()
1090 };
1091
1092 let texture = super::SurfaceTexture {
1093 index,
1094 texture: super::Texture {
1095 raw: swapchain.images[index as usize],
1096 drop_guard: None,
1097 block: None,
1098 usage: swapchain.config.usage,
1099 format: swapchain.config.format,
1100 raw_flags,
1101 copy_size: crate::CopyExtent {
1102 width: swapchain.config.extent.width,
1103 height: swapchain.config.extent.height,
1104 depth: 1,
1105 },
1106 view_formats: swapchain.view_formats.clone(),
1107 },
1108 surface_semaphores: swapchain_semaphores_arc,
1109 };
1110 Ok(Some(crate::AcquiredSurfaceTexture {
1111 texture,
1112 suboptimal,
1113 }))
1114 }
1115
1116 unsafe fn discard_texture(&self, _texture: super::SurfaceTexture) {}
1117}