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 driver_api_version(&self) -> u32 {
181 self.driver_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 required_extensions(
195 entry: &ash::Entry,
196 _driver_api_version: u32,
197 flags: crate::InstanceFlags,
198 ) -> Result<Vec<&'static CStr>, crate::InstanceError> {
199 let instance_extensions = entry
200 .enumerate_instance_extension_properties(None)
201 .map_err(|e| {
202 log::info!("enumerate_instance_extension_properties: {:?}", e);
203 crate::InstanceError
204 })?;
205
206 let mut extensions: Vec<&'static CStr> = Vec::new();
208
209 extensions.push(khr::Surface::name());
211
212 if cfg!(all(
214 unix,
215 not(target_os = "android"),
216 not(target_os = "macos")
217 )) {
218 extensions.push(khr::XlibSurface::name());
220 extensions.push(khr::XcbSurface::name());
222 extensions.push(khr::WaylandSurface::name());
224 }
225 if cfg!(target_os = "android") {
226 extensions.push(khr::AndroidSurface::name());
228 }
229 if cfg!(target_os = "windows") {
230 extensions.push(khr::Win32Surface::name());
232 }
233 if cfg!(target_os = "macos") {
234 extensions.push(ext::MetalSurface::name());
236 }
237
238 if flags.contains(crate::InstanceFlags::DEBUG) {
239 extensions.push(ext::DebugUtils::name());
241 }
242
243 extensions.push(vk::ExtSwapchainColorspaceFn::name());
246
247 extensions.push(vk::KhrGetPhysicalDeviceProperties2Fn::name());
251
252 extensions.retain(|&ext| {
254 if instance_extensions.iter().any(|inst_ext| {
255 crate::auxil::cstr_from_bytes_until_nul(&inst_ext.extension_name) == Some(ext)
256 }) {
257 true
258 } else {
259 log::info!("Unable to find extension: {}", ext.to_string_lossy());
260 false
261 }
262 });
263 Ok(extensions)
264 }
265
266 #[allow(clippy::too_many_arguments)]
277 pub unsafe fn from_raw(
278 entry: ash::Entry,
279 raw_instance: ash::Instance,
280 driver_api_version: u32,
281 android_sdk_version: u32,
282 debug_utils_user_data: Option<super::DebugUtilsMessengerUserData>,
283 extensions: Vec<&'static CStr>,
284 flags: crate::InstanceFlags,
285 has_nv_optimus: bool,
286 drop_guard: Option<crate::DropGuard>,
287 ) -> Result<Self, crate::InstanceError> {
288 log::info!("Instance version: 0x{:x}", driver_api_version);
289
290 let debug_utils = if let Some(debug_callback_user_data) = debug_utils_user_data {
291 if extensions.contains(&ext::DebugUtils::name()) {
292 log::info!("Enabling debug utils");
293 let callback_data = Box::new(debug_callback_user_data);
296
297 let extension = ext::DebugUtils::new(&entry, &raw_instance);
298 let mut severity = vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
300 if log::max_level() >= log::LevelFilter::Debug {
301 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
302 }
303 if log::max_level() >= log::LevelFilter::Info {
304 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
305 }
306 if log::max_level() >= log::LevelFilter::Warn {
307 severity |= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
308 }
309 let user_data_ptr: *const super::DebugUtilsMessengerUserData = &*callback_data;
310 let vk_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
311 .flags(vk::DebugUtilsMessengerCreateFlagsEXT::empty())
312 .message_severity(severity)
313 .message_type(
314 vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
315 | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
316 | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
317 )
318 .pfn_user_callback(Some(debug_utils_messenger_callback))
319 .user_data(user_data_ptr as *mut _);
320 let messenger =
321 unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
322 Some(super::DebugUtils {
323 extension,
324 messenger,
325 callback_data,
326 })
327 } else {
328 log::info!("Debug utils not enabled: extension not listed");
329 None
330 }
331 } else {
332 log::info!(
333 "Debug utils not enabled: \
334 debug_utils_user_data not passed to Instance::from_raw"
335 );
336 None
337 };
338
339 let get_physical_device_properties =
340 if extensions.contains(&khr::GetPhysicalDeviceProperties2::name()) {
341 log::info!("Enabling device properties2");
342 Some(khr::GetPhysicalDeviceProperties2::new(
343 &entry,
344 &raw_instance,
345 ))
346 } else {
347 None
348 };
349
350 Ok(Self {
351 shared: Arc::new(super::InstanceShared {
352 raw: raw_instance,
353 extensions,
354 drop_guard,
355 flags,
356 debug_utils,
357 get_physical_device_properties,
358 entry,
359 has_nv_optimus,
360 driver_api_version,
361 android_sdk_version,
362 }),
363 })
364 }
365
366 #[allow(dead_code)]
367 fn create_surface_from_xlib(
368 &self,
369 dpy: *mut vk::Display,
370 window: vk::Window,
371 ) -> Result<super::Surface, crate::InstanceError> {
372 if !self.shared.extensions.contains(&khr::XlibSurface::name()) {
373 log::warn!("Vulkan driver does not support VK_KHR_xlib_surface");
374 return Err(crate::InstanceError);
375 }
376
377 let surface = {
378 let xlib_loader = khr::XlibSurface::new(&self.shared.entry, &self.shared.raw);
379 let info = vk::XlibSurfaceCreateInfoKHR::builder()
380 .flags(vk::XlibSurfaceCreateFlagsKHR::empty())
381 .window(window)
382 .dpy(dpy);
383
384 unsafe { xlib_loader.create_xlib_surface(&info, None) }
385 .expect("XlibSurface::create_xlib_surface() failed")
386 };
387
388 Ok(self.create_surface_from_vk_surface_khr(surface))
389 }
390
391 #[allow(dead_code)]
392 fn create_surface_from_xcb(
393 &self,
394 connection: *mut vk::xcb_connection_t,
395 window: vk::xcb_window_t,
396 ) -> Result<super::Surface, crate::InstanceError> {
397 if !self.shared.extensions.contains(&khr::XcbSurface::name()) {
398 log::warn!("Vulkan driver does not support VK_KHR_xcb_surface");
399 return Err(crate::InstanceError);
400 }
401
402 let surface = {
403 let xcb_loader = khr::XcbSurface::new(&self.shared.entry, &self.shared.raw);
404 let info = vk::XcbSurfaceCreateInfoKHR::builder()
405 .flags(vk::XcbSurfaceCreateFlagsKHR::empty())
406 .window(window)
407 .connection(connection);
408
409 unsafe { xcb_loader.create_xcb_surface(&info, None) }
410 .expect("XcbSurface::create_xcb_surface() failed")
411 };
412
413 Ok(self.create_surface_from_vk_surface_khr(surface))
414 }
415
416 #[allow(dead_code)]
417 fn create_surface_from_wayland(
418 &self,
419 display: *mut c_void,
420 surface: *mut c_void,
421 ) -> Result<super::Surface, crate::InstanceError> {
422 if !self
423 .shared
424 .extensions
425 .contains(&khr::WaylandSurface::name())
426 {
427 log::debug!("Vulkan driver does not support VK_KHR_wayland_surface");
428 return Err(crate::InstanceError);
429 }
430
431 let surface = {
432 let w_loader = khr::WaylandSurface::new(&self.shared.entry, &self.shared.raw);
433 let info = vk::WaylandSurfaceCreateInfoKHR::builder()
434 .flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
435 .display(display)
436 .surface(surface);
437
438 unsafe { w_loader.create_wayland_surface(&info, None) }.expect("WaylandSurface failed")
439 };
440
441 Ok(self.create_surface_from_vk_surface_khr(surface))
442 }
443
444 #[allow(dead_code)]
445 fn create_surface_android(
446 &self,
447 window: *const c_void,
448 ) -> Result<super::Surface, crate::InstanceError> {
449 if !self
450 .shared
451 .extensions
452 .contains(&khr::AndroidSurface::name())
453 {
454 log::warn!("Vulkan driver does not support VK_KHR_android_surface");
455 return Err(crate::InstanceError);
456 }
457
458 let surface = {
459 let a_loader = khr::AndroidSurface::new(&self.shared.entry, &self.shared.raw);
460 let info = vk::AndroidSurfaceCreateInfoKHR::builder()
461 .flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
462 .window(window as *mut _);
463
464 unsafe { a_loader.create_android_surface(&info, None) }.expect("AndroidSurface failed")
465 };
466
467 Ok(self.create_surface_from_vk_surface_khr(surface))
468 }
469
470 #[allow(dead_code)]
471 fn create_surface_from_hwnd(
472 &self,
473 hinstance: *mut c_void,
474 hwnd: *mut c_void,
475 ) -> Result<super::Surface, crate::InstanceError> {
476 if !self.shared.extensions.contains(&khr::Win32Surface::name()) {
477 log::debug!("Vulkan driver does not support VK_KHR_win32_surface");
478 return Err(crate::InstanceError);
479 }
480
481 let surface = {
482 let info = vk::Win32SurfaceCreateInfoKHR::builder()
483 .flags(vk::Win32SurfaceCreateFlagsKHR::empty())
484 .hinstance(hinstance)
485 .hwnd(hwnd);
486 let win32_loader = khr::Win32Surface::new(&self.shared.entry, &self.shared.raw);
487 unsafe {
488 win32_loader
489 .create_win32_surface(&info, None)
490 .expect("Unable to create Win32 surface")
491 }
492 };
493
494 Ok(self.create_surface_from_vk_surface_khr(surface))
495 }
496
497 #[cfg(any(target_os = "macos", target_os = "ios"))]
498 fn create_surface_from_view(
499 &self,
500 view: *mut c_void,
501 ) -> Result<super::Surface, crate::InstanceError> {
502 if !self.shared.extensions.contains(&ext::MetalSurface::name()) {
503 log::warn!("Vulkan driver does not support VK_EXT_metal_surface");
504 return Err(crate::InstanceError);
505 }
506
507 let layer = unsafe {
508 crate::metal::Surface::get_metal_layer(view as *mut objc::runtime::Object, None)
509 };
510
511 let surface = {
512 let metal_loader = ext::MetalSurface::new(&self.shared.entry, &self.shared.raw);
513 let vk_info = vk::MetalSurfaceCreateInfoEXT::builder()
514 .flags(vk::MetalSurfaceCreateFlagsEXT::empty())
515 .layer(layer as *mut _)
516 .build();
517
518 unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() }
519 };
520
521 Ok(self.create_surface_from_vk_surface_khr(surface))
522 }
523
524 fn create_surface_from_vk_surface_khr(&self, surface: vk::SurfaceKHR) -> super::Surface {
525 let functor = khr::Surface::new(&self.shared.entry, &self.shared.raw);
526 super::Surface {
527 raw: surface,
528 functor,
529 instance: Arc::clone(&self.shared),
530 swapchain: None,
531 }
532 }
533}
534
535impl Drop for super::InstanceShared {
536 fn drop(&mut self) {
537 unsafe {
538 if let Some(du) = self.debug_utils.take() {
539 du.extension
540 .destroy_debug_utils_messenger(du.messenger, None);
541 }
542 if let Some(_drop_guard) = self.drop_guard.take() {
543 self.raw.destroy_instance(None);
544 }
545 }
546 }
547}
548
549impl crate::Instance<super::Api> for super::Instance {
550 unsafe fn init(desc: &crate::InstanceDescriptor) -> Result<Self, crate::InstanceError> {
551 use crate::auxil::cstr_from_bytes_until_nul;
552
553 let entry = match unsafe { ash::Entry::load() } {
554 Ok(entry) => entry,
555 Err(err) => {
556 log::info!("Missing Vulkan entry points: {:?}", err);
557 return Err(crate::InstanceError);
558 }
559 };
560 let driver_api_version = match entry.try_enumerate_instance_version() {
561 Ok(Some(version)) => version,
563 Ok(None) => vk::API_VERSION_1_0,
564 Err(err) => {
565 log::warn!("try_enumerate_instance_version: {:?}", err);
566 return Err(crate::InstanceError);
567 }
568 };
569
570 let app_name = CString::new(desc.name).unwrap();
571 let app_info = vk::ApplicationInfo::builder()
572 .application_name(app_name.as_c_str())
573 .application_version(1)
574 .engine_name(CStr::from_bytes_with_nul(b"wgpu-hal\0").unwrap())
575 .engine_version(2)
576 .api_version(
577 if driver_api_version < vk::API_VERSION_1_1 {
579 vk::API_VERSION_1_0
580 } else {
581 vk::HEADER_VERSION_COMPLETE
590 },
591 );
592
593 let extensions = Self::required_extensions(&entry, driver_api_version, desc.flags)?;
594
595 let instance_layers = entry.enumerate_instance_layer_properties().map_err(|e| {
596 log::info!("enumerate_instance_layer_properties: {:?}", e);
597 crate::InstanceError
598 })?;
599
600 fn find_layer<'layers>(
601 instance_layers: &'layers [vk::LayerProperties],
602 name: &CStr,
603 ) -> Option<&'layers vk::LayerProperties> {
604 instance_layers
605 .iter()
606 .find(|inst_layer| cstr_from_bytes_until_nul(&inst_layer.layer_name) == Some(name))
607 }
608
609 let nv_optimus_layer = CStr::from_bytes_with_nul(b"VK_LAYER_NV_optimus\0").unwrap();
610 let has_nv_optimus = find_layer(&instance_layers, nv_optimus_layer).is_some();
611
612 let obs_layer = CStr::from_bytes_with_nul(b"VK_LAYER_OBS_HOOK\0").unwrap();
613 let has_obs_layer = find_layer(&instance_layers, obs_layer).is_some();
614
615 let mut layers: Vec<&'static CStr> = Vec::new();
616
617 let mut debug_callback_user_data = None;
619 if desc.flags.contains(crate::InstanceFlags::VALIDATION) {
620 let validation_layer_name =
621 CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap();
622 if let Some(layer_properties) = find_layer(&instance_layers, validation_layer_name) {
623 layers.push(validation_layer_name);
624 debug_callback_user_data = Some(super::DebugUtilsMessengerUserData {
625 validation_layer_description: cstr_from_bytes_until_nul(
626 &layer_properties.description,
627 )
628 .unwrap()
629 .to_owned(),
630 validation_layer_spec_version: layer_properties.spec_version,
631 has_obs_layer,
632 });
633 } else {
634 log::warn!(
635 "InstanceFlags::VALIDATION requested, but unable to find layer: {}",
636 validation_layer_name.to_string_lossy()
637 );
638 }
639 }
640
641 #[cfg(target_os = "android")]
642 let android_sdk_version = {
643 let properties = android_system_properties::AndroidSystemProperties::new();
644 if let Some(val) = properties.get("ro.build.version.sdk") {
646 match val.parse::<u32>() {
647 Ok(sdk_ver) => sdk_ver,
648 Err(err) => {
649 log::error!(
650 "Couldn't parse Android's ro.build.version.sdk system property ({val}): {err}"
651 );
652 0
653 }
654 }
655 } else {
656 log::error!("Couldn't read Android's ro.build.version.sdk system property");
657 0
658 }
659 };
660 #[cfg(not(target_os = "android"))]
661 let android_sdk_version = 0;
662
663 let vk_instance = {
664 let str_pointers = layers
665 .iter()
666 .chain(extensions.iter())
667 .map(|&s| {
668 s.as_ptr()
670 })
671 .collect::<Vec<_>>();
672
673 let create_info = vk::InstanceCreateInfo::builder()
674 .flags(vk::InstanceCreateFlags::empty())
675 .application_info(&app_info)
676 .enabled_layer_names(&str_pointers[..layers.len()])
677 .enabled_extension_names(&str_pointers[layers.len()..]);
678
679 unsafe { entry.create_instance(&create_info, None) }.map_err(|e| {
680 log::warn!("create_instance: {:?}", e);
681 crate::InstanceError
682 })?
683 };
684
685 unsafe {
686 Self::from_raw(
687 entry,
688 vk_instance,
689 driver_api_version,
690 android_sdk_version,
691 debug_callback_user_data,
692 extensions,
693 desc.flags,
694 has_nv_optimus,
695 Some(Box::new(())), )
697 }
698 }
699
700 unsafe fn create_surface(
701 &self,
702 display_handle: raw_window_handle::RawDisplayHandle,
703 window_handle: raw_window_handle::RawWindowHandle,
704 ) -> Result<super::Surface, crate::InstanceError> {
705 use raw_window_handle::{RawDisplayHandle as Rdh, RawWindowHandle as Rwh};
706
707 match (window_handle, display_handle) {
708 (Rwh::Wayland(handle), Rdh::Wayland(display)) => {
709 self.create_surface_from_wayland(display.display, handle.surface)
710 }
711 (Rwh::Xlib(handle), Rdh::Xlib(display)) => {
712 self.create_surface_from_xlib(display.display as *mut _, handle.window)
713 }
714 (Rwh::Xcb(handle), Rdh::Xcb(display)) => {
715 self.create_surface_from_xcb(display.connection, handle.window)
716 }
717 (Rwh::AndroidNdk(handle), _) => self.create_surface_android(handle.a_native_window),
718 #[cfg(windows)]
719 (Rwh::Win32(handle), _) => {
720 use winapi::um::libloaderapi::GetModuleHandleW;
721
722 let hinstance = unsafe { GetModuleHandleW(std::ptr::null()) };
723 self.create_surface_from_hwnd(hinstance as *mut _, handle.hwnd)
724 }
725 #[cfg(target_os = "macos")]
726 (Rwh::AppKit(handle), _)
727 if self.shared.extensions.contains(&ext::MetalSurface::name()) =>
728 {
729 self.create_surface_from_view(handle.ns_view)
730 }
731 #[cfg(target_os = "ios")]
732 (Rwh::UiKit(handle), _)
733 if self.shared.extensions.contains(&ext::MetalSurface::name()) =>
734 {
735 self.create_surface_from_view(handle.ui_view)
736 }
737 (_, _) => Err(crate::InstanceError),
738 }
739 }
740
741 unsafe fn destroy_surface(&self, surface: super::Surface) {
742 unsafe { surface.functor.destroy_surface(surface.raw, None) };
743 }
744
745 unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<super::Api>> {
746 use crate::auxil::db;
747
748 let raw_devices = match unsafe { self.shared.raw.enumerate_physical_devices() } {
749 Ok(devices) => devices,
750 Err(err) => {
751 log::error!("enumerate_adapters: {}", err);
752 Vec::new()
753 }
754 };
755
756 let mut exposed_adapters = raw_devices
757 .into_iter()
758 .flat_map(|device| self.expose_adapter(device))
759 .collect::<Vec<_>>();
760
761 let has_nvidia_dgpu = exposed_adapters.iter().any(|exposed| {
763 exposed.info.device_type == wgt::DeviceType::DiscreteGpu
764 && exposed.info.vendor == db::nvidia::VENDOR
765 });
766 if cfg!(target_os = "linux") && has_nvidia_dgpu && self.shared.has_nv_optimus {
767 for exposed in exposed_adapters.iter_mut() {
768 if exposed.info.device_type == wgt::DeviceType::IntegratedGpu
769 && exposed.info.vendor == db::intel::VENDOR
770 {
771 log::warn!(
773 "Disabling presentation on '{}' (id {:?}) because of NV Optimus (on Linux)",
774 exposed.info.name,
775 exposed.adapter.raw
776 );
777 exposed.adapter.private_caps.can_present = false;
778 }
779 }
780 }
781
782 exposed_adapters
783 }
784}
785
786impl crate::Surface<super::Api> for super::Surface {
787 unsafe fn configure(
788 &mut self,
789 device: &super::Device,
790 config: &crate::SurfaceConfiguration,
791 ) -> Result<(), crate::SurfaceError> {
792 let old = self
794 .swapchain
795 .take()
796 .map(|sc| unsafe { sc.release_resources(&device.shared.raw) });
797
798 let swapchain = unsafe { device.create_swapchain(self, config, old)? };
799 self.swapchain = Some(swapchain);
800
801 Ok(())
802 }
803
804 unsafe fn unconfigure(&mut self, device: &super::Device) {
805 if let Some(sc) = self.swapchain.take() {
806 let swapchain = unsafe { sc.release_resources(&device.shared.raw) };
808 unsafe { swapchain.functor.destroy_swapchain(swapchain.raw, None) };
809 }
810 }
811
812 unsafe fn acquire_texture(
813 &mut self,
814 timeout: Option<std::time::Duration>,
815 ) -> Result<Option<crate::AcquiredSurfaceTexture<super::Api>>, crate::SurfaceError> {
816 let sc = self.swapchain.as_mut().unwrap();
817
818 let mut timeout_ns = match timeout {
819 Some(duration) => duration.as_nanos() as u64,
820 None => u64::MAX,
821 };
822
823 if cfg!(target_os = "android") && self.instance.android_sdk_version < 30 {
833 timeout_ns = u64::MAX;
834 }
835
836 let (index, suboptimal) = match unsafe {
838 sc.functor
839 .acquire_next_image(sc.raw, timeout_ns, vk::Semaphore::null(), sc.fence)
840 } {
841 #[cfg(target_os = "android")]
844 Ok((index, _)) => (index, false),
845 #[cfg(not(target_os = "android"))]
846 Ok(pair) => pair,
847 Err(error) => {
848 return match error {
849 vk::Result::TIMEOUT => Ok(None),
850 vk::Result::NOT_READY | vk::Result::ERROR_OUT_OF_DATE_KHR => {
851 Err(crate::SurfaceError::Outdated)
852 }
853 vk::Result::ERROR_SURFACE_LOST_KHR => Err(crate::SurfaceError::Lost),
854 other => Err(crate::DeviceError::from(other).into()),
855 }
856 }
857 };
858
859 if sc.device.vendor_id == crate::auxil::db::intel::VENDOR && index > 0x100 {
861 return Err(crate::SurfaceError::Outdated);
862 }
863
864 let fences = &[sc.fence];
865
866 unsafe { sc.device.raw.wait_for_fences(fences, true, !0) }
867 .map_err(crate::DeviceError::from)?;
868 unsafe { sc.device.raw.reset_fences(fences) }.map_err(crate::DeviceError::from)?;
869
870 let raw_flags = if sc
872 .raw_flags
873 .contains(vk::SwapchainCreateFlagsKHR::MUTABLE_FORMAT)
874 {
875 vk::ImageCreateFlags::MUTABLE_FORMAT | vk::ImageCreateFlags::EXTENDED_USAGE
876 } else {
877 vk::ImageCreateFlags::empty()
878 };
879
880 let texture = super::SurfaceTexture {
881 index,
882 texture: super::Texture {
883 raw: sc.images[index as usize],
884 drop_guard: None,
885 block: None,
886 usage: sc.config.usage,
887 format: sc.config.format,
888 raw_flags,
889 copy_size: crate::CopyExtent {
890 width: sc.config.extent.width,
891 height: sc.config.extent.height,
892 depth: 1,
893 },
894 view_formats: sc.view_formats.clone(),
895 },
896 };
897 Ok(Some(crate::AcquiredSurfaceTexture {
898 texture,
899 suboptimal,
900 }))
901 }
902
903 unsafe fn discard_texture(&mut self, _texture: super::SurfaceTexture) {}
904}