1use std::{
2 ffi::{c_void, CStr, CString},
3 slice,
4 sync::Arc,
5 thread,
6};
7
8use ash::{
9 extensions::{ext, khr},
10 vk,
11};
12
13unsafe extern "system" fn debug_utils_messenger_callback(
14 message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
15 message_type: vk::DebugUtilsMessageTypeFlagsEXT,
16 callback_data_ptr: *const vk::DebugUtilsMessengerCallbackDataEXT,
17 user_data: *mut c_void,
18) -> vk::Bool32 {
19 use std::borrow::Cow;
20
21 if thread::panicking() {
22 return vk::FALSE;
23 }
24
25 let cd = unsafe { &*callback_data_ptr };
26 let user_data = unsafe { &*(user_data as *mut super::DebugUtilsMessengerUserData) };
27
28 const VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912: i32 = 0x56146426;
29 if cd.message_id_number == VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912 {
30 let khronos_validation_layer =
34 std::ffi::CStr::from_bytes_with_nul(b"Khronos Validation Layer\0").unwrap();
35 if user_data.validation_layer_description.as_ref() == khronos_validation_layer
36 && user_data.validation_layer_spec_version >= vk::make_api_version(0, 1, 3, 240)
37 && user_data.validation_layer_spec_version <= vk::make_api_version(0, 1, 3, 250)
38 {
39 return vk::FALSE;
40 }
41 }
42
43 const VUID_VKSWAPCHAINCREATEINFOKHR_IMAGEEXTENT_01274: i32 = 0x7cd0911d;
46 if cd.message_id_number == VUID_VKSWAPCHAINCREATEINFOKHR_IMAGEEXTENT_01274 {
47 return vk::FALSE;
48 }
49
50 const VUID_VKRENDERPASSBEGININFO_FRAMEBUFFER_04627: i32 = 0x45125641;
57 if cd.message_id_number == VUID_VKRENDERPASSBEGININFO_FRAMEBUFFER_04627
58 && user_data.has_obs_layer
59 {
60 return vk::FALSE;
61 }
62
63 let level = match message_severity {
64 vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => log::Level::Debug,
65 vk::DebugUtilsMessageSeverityFlagsEXT::INFO => log::Level::Info,
66 vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => log::Level::Warn,
67 vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => log::Level::Error,
68 _ => log::Level::Warn,
69 };
70
71 let message_id_name = if cd.p_message_id_name.is_null() {
72 Cow::from("")
73 } else {
74 unsafe { CStr::from_ptr(cd.p_message_id_name) }.to_string_lossy()
75 };
76 let message = if cd.p_message.is_null() {
77 Cow::from("")
78 } else {
79 unsafe { CStr::from_ptr(cd.p_message) }.to_string_lossy()
80 };
81
82 let _ = std::panic::catch_unwind(|| {
83 log::log!(
84 level,
85 "{:?} [{} (0x{:x})]\n\t{}",
86 message_type,
87 message_id_name,
88 cd.message_id_number,
89 message,
90 );
91 });
92
93 if cd.queue_label_count != 0 {
94 let labels =
95 unsafe { slice::from_raw_parts(cd.p_queue_labels, cd.queue_label_count as usize) };
96 let names = labels
97 .iter()
98 .flat_map(|dul_obj| {
99 unsafe { dul_obj.p_label_name.as_ref() }
100 .map(|lbl| unsafe { CStr::from_ptr(lbl) }.to_string_lossy())
101 })
102 .collect::<Vec<_>>();
103
104 let _ = std::panic::catch_unwind(|| {
105 log::log!(level, "\tqueues: {}", names.join(", "));
106 });
107 }
108
109 if cd.cmd_buf_label_count != 0 {
110 let labels =
111 unsafe { slice::from_raw_parts(cd.p_cmd_buf_labels, cd.cmd_buf_label_count as usize) };
112 let names = labels
113 .iter()
114 .flat_map(|dul_obj| {
115 unsafe { dul_obj.p_label_name.as_ref() }
116 .map(|lbl| unsafe { CStr::from_ptr(lbl) }.to_string_lossy())
117 })
118 .collect::<Vec<_>>();
119
120 let _ = std::panic::catch_unwind(|| {
121 log::log!(level, "\tcommand buffers: {}", names.join(", "));
122 });
123 }
124
125 if cd.object_count != 0 {
126 let labels = unsafe { slice::from_raw_parts(cd.p_objects, cd.object_count as usize) };
127 let names = labels
129 .iter()
130 .map(|obj_info| {
131 let name = unsafe { obj_info.p_object_name.as_ref() }
132 .map(|name| unsafe { CStr::from_ptr(name) }.to_string_lossy())
133 .unwrap_or(Cow::Borrowed("?"));
134
135 format!(
136 "(type: {:?}, hndl: 0x{:x}, name: {})",
137 obj_info.object_type, obj_info.object_handle, name
138 )
139 })
140 .collect::<Vec<_>>();
141 let _ = std::panic::catch_unwind(|| {
142 log::log!(level, "\tobjects: {}", names.join(", "));
143 });
144 }
145
146 if cfg!(debug_assertions) && level == log::Level::Error {
147 crate::VALIDATION_CANARY.set();
149 }
150
151 vk::FALSE
152}
153
154impl super::Swapchain {
155 unsafe fn release_resources(self, device: &ash::Device) -> Self {
159 profiling::scope!("Swapchain::release_resources");
160 {
161 profiling::scope!("vkDeviceWaitIdle");
162 let _ = unsafe { device.device_wait_idle() };
165 };
166 unsafe { device.destroy_fence(self.fence, None) };
167 self
168 }
169}
170
171impl super::InstanceShared {
172 pub fn entry(&self) -> &ash::Entry {
173 &self.entry
174 }
175
176 pub fn raw_instance(&self) -> &ash::Instance {
177 &self.raw
178 }
179
180 pub fn instance_api_version(&self) -> u32 {
181 self.instance_api_version
182 }
183
184 pub fn extensions(&self) -> &[&'static CStr] {
185 &self.extensions[..]
186 }
187}
188
189impl super::Instance {
190 pub fn shared_instance(&self) -> &super::InstanceShared {
191 &self.shared
192 }
193
194 pub fn desired_extensions(
208 entry: &ash::Entry,
209 _instance_api_version: u32,
210 flags: wgt::InstanceFlags,
211 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
212 let instance_extensions = entry
213 .enumerate_instance_extension_properties(None)
214 .map_err(|e| {
215 crate::InstanceError::with_source(
216 String::from("enumerate_instance_extension_properties() failed"),
217 e,
218 )
219 })?;
220
221 let mut extensions: Vec<&'static CStr> = Vec::new();
223
224 extensions.push(khr::Surface::name());
226
227 if cfg!(all(
229 unix,
230 not(target_os = "android"),
231 not(target_os = "macos")
232 )) {
233 extensions.push(khr::XlibSurface::name());
235 extensions.push(khr::XcbSurface::name());
237 extensions.push(khr::WaylandSurface::name());
239 }
240 if cfg!(target_os = "android") {
241 extensions.push(khr::AndroidSurface::name());
243 }
244 if cfg!(target_os = "windows") {
245 extensions.push(khr::Win32Surface::name());
247 }
248 if cfg!(target_os = "macos") {
249 extensions.push(ext::MetalSurface::name());
251 extensions.push(ash::vk::KhrPortabilityEnumerationFn::name());
252 }
253
254 if flags.contains(wgt::InstanceFlags::DEBUG) {
255 extensions.push(ext::DebugUtils::name());
257 }
258
259 extensions.push(vk::ExtSwapchainColorspaceFn::name());
262
263 extensions.push(vk::KhrGetPhysicalDeviceProperties2Fn::name());
267
268 extensions.retain(|&ext| {
270 if instance_extensions.iter().any(|inst_ext| {
271 crate::auxil::cstr_from_bytes_until_nul(&inst_ext.extension_name) == Some(ext)
272 }) {
273 true
274 } else {
275 log::info!("Unable to find extension: {}", ext.to_string_lossy());
276 false
277 }
278 });
279 Ok(extensions)
280 }
281
282 #[allow(clippy::too_many_arguments)]
293 pub unsafe fn from_raw(
294 entry: ash::Entry,
295 raw_instance: ash::Instance,
296 instance_api_version: u32,
297 android_sdk_version: u32,
298 debug_utils_user_data: Option<super::DebugUtilsMessengerUserData>,
299 extensions: Vec<&'static CStr>,
300 flags: wgt::InstanceFlags,
301 has_nv_optimus: bool,
302 drop_guard: Option<crate::DropGuard>,
303 ) -> Result<Self, crate::InstanceError> {
304 log::info!("Instance version: 0x{:x}", instance_api_version);
305
306 let debug_utils = if let Some(debug_callback_user_data) = debug_utils_user_data {
307 if extensions.contains(&ext::DebugUtils::name()) {
308 log::info!("Enabling debug utils");
309 let callback_data = Box::new(debug_callback_user_data);
312
313 let extension = ext::DebugUtils::new(&entry, &raw_instance);
314 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
316 if log::max_level() >= log::LevelFilter::Debug {
317 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
318 }
319 if log::max_level() >= log::LevelFilter::Info {
320 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
321 }
322 if log::max_level() >= log::LevelFilter::Warn {
323 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
324 }
325 let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*callback_data;
326 let vk_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
327 .flags(vk::DebugUtilsMessengerCreateFlagsEXT::empty())
328 .message_severity(severity)
329 .message_type(
330 vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
331 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
332 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
333 )
334 .pfn_user_callback(Some(debug_utils_messenger_callback))
335 .user_data(user_data_ptr as *mut _);
336 let messenger =
337 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
338 Some(super::DebugUtils {
339 extension,
340 messenger,
341 callback_data,
342 })
343 } else {
344 log::info!("Debug utils not enabled: extension not listed");
345 None
346 }
347 } else {
348 log::info!(
349 "Debug utils not enabled: \
350 debug_utils_user_data not passed to Instance::from_raw"
351 );
352 None
353 };
354
355 let get_physical_device_properties =
356 if extensions.contains(&khr::GetPhysicalDeviceProperties2::name()) {
357 log::info!("Enabling device properties2");
358 Some(khr::GetPhysicalDeviceProperties2::new(
359 &entry,
360 &raw_instance,
361 ))
362 } else {
363 None
364 };
365
366 Ok(Self {
367 shared: Arc::new(super::InstanceShared {
368 raw: raw_instance,
369 extensions,
370 drop_guard,
371 flags,
372 debug_utils,
373 get_physical_device_properties,
374 entry,
375 has_nv_optimus,
376 instance_api_version,
377 android_sdk_version,
378 }),
379 })
380 }
381
382 #[allow(dead_code)]
383 fn create_surface_from_xlib(
384 &self,
385 dpy: *mut vk::Display,
386 window: vk::Window,
387 ) -> Result<super::Surface, crate::InstanceError> {
388 if !self.shared.extensions.contains(&khr::XlibSurface::name()) {
389 return Err(crate::InstanceError::new(String::from(
390 "Vulkan driver does not support VK_KHR_xlib_surface",
391 )));
392 }
393
394 let surface = {
395 let xlib_loader = khr::XlibSurface::new(&self.shared.entry, &self.shared.raw);
396 let info = vk::XlibSurfaceCreateInfoKHR::builder()
397 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
398 .window(window)
399 .dpy(dpy);
400
401 unsafe { xlib_loader.create_xlib_surface(&info, None) }
402 .expect("XlibSurface::create_xlib_surface() failed")
403 };
404
405 Ok(self.create_surface_from_vk_surface_khr(surface))
406 }
407
408 #[allow(dead_code)]
409 fn create_surface_from_xcb(
410 &self,
411 connection: *mut vk::xcb_connection_t,
412 window: vk::xcb_window_t,
413 ) -> Result<super::Surface, crate::InstanceError> {
414 if !self.shared.extensions.contains(&khr::XcbSurface::name()) {
415 return Err(crate::InstanceError::new(String::from(
416 "Vulkan driver does not support VK_KHR_xcb_surface",
417 )));
418 }
419
420 let surface = {
421 let xcb_loader = khr::XcbSurface::new(&self.shared.entry, &self.shared.raw);
422 let info = vk::XcbSurfaceCreateInfoKHR::builder()
423 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
424 .window(window)
425 .connection(connection);
426
427 unsafe { xcb_loader.create_xcb_surface(&info, None) }
428 .expect("XcbSurface::create_xcb_surface() failed")
429 };
430
431 Ok(self.create_surface_from_vk_surface_khr(surface))
432 }
433
434 #[allow(dead_code)]
435 fn create_surface_from_wayland(
436 &self,
437 display: *mut c_void,
438 surface: *mut c_void,
439 ) -> Result<super::Surface, crate::InstanceError> {
440 if !self
441 .shared
442 .extensions
443 .contains(&khr::WaylandSurface::name())
444 {
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 = khr::WaylandSurface::new(&self.shared.entry, &self.shared.raw);
452 let info = vk::WaylandSurfaceCreateInfoKHR::builder()
453 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
454 .display(display)
455 .surface(surface);
456
457 unsafe { w_loader.create_wayland_surface(&info, None) }.expect("WaylandSurface failed")
458 };
459
460 Ok(self.create_surface_from_vk_surface_khr(surface))
461 }
462
463 #[allow(dead_code)]
464 fn create_surface_android(
465 &self,
466 window: *const c_void,
467 ) -> Result<super::Surface, crate::InstanceError> {
468 if !self
469 .shared
470 .extensions
471 .contains(&khr::AndroidSurface::name())
472 {
473 return Err(crate::InstanceError::new(String::from(
474 "Vulkan driver does not support VK_KHR_android_surface",
475 )));
476 }
477
478 let surface = {
479 let a_loader = khr::AndroidSurface::new(&self.shared.entry, &self.shared.raw);
480 let info = vk::AndroidSurfaceCreateInfoKHR::builder()
481 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
482 .window(window as *mut _);
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 #[allow(dead_code)]
491 fn create_surface_from_hwnd(
492 &self,
493 hinstance: *mut c_void,
494 hwnd: *mut c_void,
495 ) -> Result<super::Surface, crate::InstanceError> {
496 if !self.shared.extensions.contains(&khr::Win32Surface::name()) {
497 return Err(crate::InstanceError::new(String::from(
498 "Vulkan driver does not support VK_KHR_win32_surface",
499 )));
500 }
501
502 let surface = {
503 let info = vk::Win32SurfaceCreateInfoKHR::builder()
504 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
505 .hinstance(hinstance)
506 .hwnd(hwnd);
507 let win32_loader = khr::Win32Surface::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(any(target_os = "macos", target_os = "ios"))]
519 fn create_surface_from_view(
520 &self,
521 view: *mut c_void,
522 ) -> Result<super::Surface, crate::InstanceError> {
523 if !self.shared.extensions.contains(&ext::MetalSurface::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 {
530 crate::metal::Surface::get_metal_layer(view as *mut objc::runtime::Object, None)
531 };
532
533 let surface = {
534 let metal_loader = ext::MetalSurface::new(&self.shared.entry, &self.shared.raw);
535 let vk_info = vk::MetalSurfaceCreateInfoEXT::builder()
536 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
537 .layer(layer as *mut _)
538 .build();
539
540 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
541 };
542
543 Ok(self.create_surface_from_vk_surface_khr(surface))
544 }
545
546 fn create_surface_from_vk_surface_khr(&self, surface: vk::SurfaceKHR) -> super::Surface {
547 let functor = khr::Surface::new(&self.shared.entry, &self.shared.raw);
548 super::Surface {
549 raw: surface,
550 functor,
551 instance: Arc::clone(&self.shared),
552 swapchain: None,
553 }
554 }
555}
556
557impl Drop for super::InstanceShared {
558 fn drop(&mut self) {
559 unsafe {
560 if let Some(du) = self.debug_utils.take() {
561 du.extension
562 .destroy_debug_utils_messenger(du.messenger, None);
563 }
564 if let Some(_drop_guard) = self.drop_guard.take() {
565 self.raw.destroy_instance(None);
566 }
567 }
568 }
569}
570
571impl crate::Instance<super::Api> for super::Instance {
572 unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
573 use crate::auxil::cstr_from_bytes_until_nul;
574
575 let entry = unsafe { ash::Entry::load() }.map_err(|err| {
576 crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
577 })?;
578 let instance_api_version = match entry.try_enumerate_instance_version() {
579 Ok(Some(version)) => version,
581 Ok(None) => vk::API_VERSION_1_0,
582 Err(err) => {
583 return Err(crate::InstanceError::with_source(
584 String::from("try_enumerate_instance_version() failed"),
585 err,
586 ));
587 }
588 };
589
590 let app_name = CString::new(desc.name).unwrap();
591 let app_info = vk::ApplicationInfo::builder()
592 .application_name(app_name.as_c_str())
593 .application_version(1)
594 .engine_name(CStr::from_bytes_with_nul(b"wgpu-hal\0").unwrap())
595 .engine_version(2)
596 .api_version(
597 if instance_api_version < vk::API_VERSION_1_1 {
599 vk::API_VERSION_1_0
600 } else {
601 vk::API_VERSION_1_3
610 },
611 );
612
613 let extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
614
615 let instance_layers = entry.enumerate_instance_layer_properties().map_err(|e| {
616 log::info!("enumerate_instance_layer_properties: {:?}", e);
617 crate::InstanceError::with_source(
618 String::from("enumerate_instance_layer_properties() failed"),
619 e,
620 )
621 })?;
622
623 fn find_layer<'layers>(
624 instance_layers: &'layers [vk::LayerProperties],
625 name: &CStr,
626 ) -> Option<&'layers vk::LayerProperties> {
627 instance_layers
628 .iter()
629 .find(|inst_layer| cstr_from_bytes_until_nul(&inst_layer.layer_name) == Some(name))
630 }
631
632 let nv_optimus_layer = CStr::from_bytes_with_nul(b"VK_LAYER_NV_optimus\0").unwrap();
633 let has_nv_optimus = find_layer(&instance_layers, nv_optimus_layer).is_some();
634
635 let obs_layer = CStr::from_bytes_with_nul(b"VK_LAYER_OBS_HOOK\0").unwrap();
636 let has_obs_layer = find_layer(&instance_layers, obs_layer).is_some();
637
638 let mut layers: Vec<&'static CStr> = Vec::new();
639
640 let mut debug_callback_user_data = None;
642 if desc.flags.contains(wgt::InstanceFlags::VALIDATION) {
643 let validation_layer_name =
644 CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap();
645 if let Some(layer_properties) = find_layer(&instance_layers, validation_layer_name) {
646 layers.push(validation_layer_name);
647 debug_callback_user_data = Some(super::DebugUtilsMessengerUserData {
648 validation_layer_description: cstr_from_bytes_until_nul(
649 &layer_properties.description,
650 )
651 .unwrap()
652 .to_owned(),
653 validation_layer_spec_version: layer_properties.spec_version,
654 has_obs_layer,
655 });
656 } else {
657 log::warn!(
658 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
659 validation_layer_name.to_string_lossy()
660 );
661 }
662 }
663
664 #[cfg(target_os = "android")]
665 let android_sdk_version = {
666 let properties = android_system_properties::AndroidSystemProperties::new();
667 if let Some(val) = properties.get("ro.build.version.sdk") {
669 match val.parse::<u32>() {
670 Ok(sdk_ver) => sdk_ver,
671 Err(err) => {
672 log::error!(
673 "Couldn't parse Android's ro.build.version.sdk system property ({val}): {err}"
674 );
675 0
676 }
677 }
678 } else {
679 log::error!("Couldn't read Android's ro.build.version.sdk system property");
680 0
681 }
682 };
683 #[cfg(not(target_os = "android"))]
684 let android_sdk_version = 0;
685
686 let mut flags = vk::InstanceCreateFlags::empty();
687
688 if extensions.contains(&ash::vk::KhrPortabilityEnumerationFn::name()) {
692 flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
693 }
694
695 let vk_instance = {
696 let str_pointers = layers
697 .iter()
698 .chain(extensions.iter())
699 .map(|&s| {
700 s.as_ptr()
702 })
703 .collect::<Vec<_>>();
704
705 let create_info = vk::InstanceCreateInfo::builder()
706 .flags(flags)
707 .application_info(&app_info)
708 .enabled_layer_names(&str_pointers[..layers.len()])
709 .enabled_extension_names(&str_pointers[layers.len()..]);
710
711 unsafe { entry.create_instance(&create_info, None) }.map_err(|e| {
712 crate::InstanceError::with_source(
713 String::from("Entry::create_instance() failed"),
714 e,
715 )
716 })?
717 };
718
719 unsafe {
720 Self::from_raw(
721 entry,
722 vk_instance,
723 instance_api_version,
724 android_sdk_version,
725 debug_callback_user_data,
726 extensions,
727 desc.flags,
728 has_nv_optimus,
729 Some(Box::new(())), )
731 }
732 }
733
734 unsafe fn create_surface(
735 &self,
736 display_handle: raw_window_handle::RawDisplayHandle,
737 window_handle: raw_window_handle::RawWindowHandle,
738 ) -> Result<super::Surface, crate::InstanceError> {
739 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
740
741 match (window_handle, display_handle) {
742 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
743 self.create_surface_from_wayland(display.display, handle.surface)
744 }
745 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
746 self.create_surface_from_xlib(display.display as *mut _, handle.window)
747 }
748 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
749 self.create_surface_from_xcb(display.connection, handle.window)
750 }
751 (Rwh::AndroidNdk(handle), _) => self.create_surface_android(handle.a_native_window),
752 #[cfg(windows)]
753 (Rwh::Win32(handle), _) => {
754 use winapi::um::libloaderapi::GetModuleHandleW;
755
756 let hinstance = unsafe { GetModuleHandleW(std::ptr::null()) };
757 self.create_surface_from_hwnd(hinstance as *mut _, handle.hwnd)
758 }
759 #[cfg(target_os = "macos")]
760 (Rwh::AppKit(handle), _)
761 if self.shared.extensions.contains(&ext::MetalSurface::name()) =>
762 {
763 self.create_surface_from_view(handle.ns_view)
764 }
765 #[cfg(target_os = "ios")]
766 (Rwh::UiKit(handle), _)
767 if self.shared.extensions.contains(&ext::MetalSurface::name()) =>
768 {
769 self.create_surface_from_view(handle.ui_view)
770 }
771 (_, _) => Err(crate::InstanceError::new(format!(
772 "window handle {window_handle:?} is not a Vulkan-compatible handle"
773 ))),
774 }
775 }
776
777 unsafe fn destroy_surface(&self, surface: super::Surface) {
778 unsafe { surface.functor.destroy_surface(surface.raw, None) };
779 }
780
781 unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
782 use crate::auxil::db;
783
784 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
785 Ok(devices) => devices,
786 Err(err) => {
787 log::error!("enumerate_adapters: {}", err);
788 Vec::new()
789 }
790 };
791
792 let mut exposed_adapters = raw_devices
793 .into_iter()
794 .flat_map(|device| self.expose_adapter(device))
795 .collect::<Vec<_>>();
796
797 let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| {
799 exposed.info.device_type == wgt::DeviceType::DiscreteGpu
800 && exposed.info.vendor == db::nvidia::VENDOR
801 });
802 if cfg!(target_os = "linux") && has_nvidia_dgpu && self.shared.has_nv_optimus {
803 for exposed in exposed_adapters.iter_mut() {
804 if exposed.info.device_type == wgt::DeviceType::IntegratedGpu
805 && exposed.info.vendor == db::intel::VENDOR
806 {
807 if let Some(version) = exposed.info.driver_info.split_once("Mesa ").map(|s| {
809 s.1.rsplit_once('.')
810 .map(|v| v.0.parse::<f32>().unwrap_or_default())
811 .unwrap_or_default()
812 }) {
813 if version < 21.2 {
814 log::warn!(
816 "Disabling presentation on '{}' (id {:?}) due to NV Optimus and Intel Mesa < v21.2",
817 exposed.info.name,
818 exposed.adapter.raw
819 );
820 exposed.adapter.private_caps.can_present = false;
821 }
822 }
823 }
824 }
825 }
826
827 exposed_adapters
828 }
829}
830
831impl crate::Surface<super::Api> for super::Surface {
832 unsafe fn configure(
833 &mut self,
834 device: &super::Device,
835 config: &crate::SurfaceConfiguration,
836 ) -> Result<(), crate::SurfaceError> {
837 let old = self
839 .swapchain
840 .take()
841 .map(|sc| unsafe { sc.release_resources(&device.shared.raw) });
842
843 let swapchain = unsafe { device.create_swapchain(self, config, old)? };
844 self.swapchain = Some(swapchain);
845
846 Ok(())
847 }
848
849 unsafe fn unconfigure(&mut self, device: &super::Device) {
850 if let Some(sc) = self.swapchain.take() {
851 let swapchain = unsafe { sc.release_resources(&device.shared.raw) };
853 unsafe { swapchain.functor.destroy_swapchain(swapchain.raw, None) };
854 }
855 }
856
857 unsafe fn acquire_texture(
858 &mut self,
859 timeout: Option<std::time::Duration>,
860 ) -> Result<Option<crate::AcquiredSurfaceTexture<super::Api>>, crate::SurfaceError> {
861 let sc = self.swapchain.as_mut().unwrap();
862
863 let mut timeout_ns = match timeout {
864 Some(duration) => duration.as_nanos() as u64,
865 None => u64::MAX,
866 };
867
868 if cfg!(target_os = "android") && self.instance.android_sdk_version < 30 {
878 timeout_ns = u64::MAX;
879 }
880
881 let (index, suboptimal) = match unsafe {
883 sc.functor
884 .acquire_next_image(sc.raw, timeout_ns, vk::Semaphore::null(), sc.fence)
885 } {
886 #[cfg(target_os = "android")]
889 Ok((index, _)) => (index, false),
890 #[cfg(not(target_os = "android"))]
891 Ok(pair) => pair,
892 Err(error) => {
893 return match error {
894 vk::Result::TIMEOUT => Ok(None),
895 vk::Result::NOT_READY | vk::Result::ERROR_OUT_OF_DATE_KHR => {
896 Err(crate::SurfaceError::Outdated)
897 }
898 vk::Result::ERROR_SURFACE_LOST_KHR => Err(crate::SurfaceError::Lost),
899 other => Err(crate::DeviceError::from(other).into()),
900 }
901 }
902 };
903
904 if sc.device.vendor_id == crate::auxil::db::intel::VENDOR && index > 0x100 {
906 return Err(crate::SurfaceError::Outdated);
907 }
908
909 let fences = &[sc.fence];
910
911 unsafe { sc.device.raw.wait_for_fences(fences, true, !0) }
912 .map_err(crate::DeviceError::from)?;
913 unsafe { sc.device.raw.reset_fences(fences) }.map_err(crate::DeviceError::from)?;
914
915 let raw_flags = if sc
917 .raw_flags
918 .contains(vk::SwapchainCreateFlagsKHR::MUTABLE_FORMAT)
919 {
920 vk::ImageCreateFlags::MUTABLE_FORMAT | vk::ImageCreateFlags::EXTENDED_USAGE
921 } else {
922 vk::ImageCreateFlags::empty()
923 };
924
925 let texture = super::SurfaceTexture {
926 index,
927 texture: super::Texture {
928 raw: sc.images[index as usize],
929 drop_guard: None,
930 block: None,
931 usage: sc.config.usage,
932 format: sc.config.format,
933 raw_flags,
934 copy_size: crate::CopyExtent {
935 width: sc.config.extent.width,
936 height: sc.config.extent.height,
937 depth: 1,
938 },
939 view_formats: sc.view_formats.clone(),
940 },
941 };
942 Ok(Some(crate::AcquiredSurfaceTexture {
943 texture,
944 suboptimal,
945 }))
946 }
947
948 unsafe fn discard_texture(&mut self, _texture: super::SurfaceTexture) {}
949}