diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fd4e5348e..166524e6cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -100,6 +100,8 @@ SurfaceConfiguration { violates Vulkan valid usage rules `VUID-StandaloneSpirv-Flat-06202` and `VUID-StandaloneSpirv-Flat-04744`. By @jimblandy in [#3008](https://github.com/gfx-rs/wgpu/pull/3008) +- Fix bug where the Vulkan backend would panic when using a supported window and display handle but the + dependent extensions are not available by @i509VCB in [#3054](https://github.com/gfx-rs/wgpu/pull/3054). #### Gles - Report vendor id for Mesa and Apple GPUs. By @i509VCB [#3036](https://github.com/gfx-rs/wgpu/pull/3036) diff --git a/Cargo.lock b/Cargo.lock index 5e2ac814c2..6eda8fa13c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,12 +337,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "copyless" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" - [[package]] name = "core-foundation" version = "0.9.3" @@ -2249,7 +2243,6 @@ dependencies = [ "bitflags", "cfg_aliases", "codespan-reporting", - "copyless", "fxhash", "log", "naga", diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index b3674170c4..072e14620a 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -5186,7 +5186,7 @@ impl Global { let caps = unsafe { let suf = A::get_surface(surface); let adapter = &adapter_guard[device.adapter_id.value]; - match adapter.raw.adapter.surface_capabilities(&suf.raw) { + match adapter.raw.adapter.surface_capabilities(&suf.unwrap().raw) { Some(caps) => caps, None => break E::UnsupportedQueueFamily, } @@ -5214,6 +5214,7 @@ impl Global { match unsafe { A::get_surface_mut(surface) + .unwrap() .raw .configure(&device.raw, &hal_config) } { diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 2b085b7e05..8e256e7c32 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -1007,7 +1007,7 @@ impl Hub { let device = &devices[present.device_id.value]; let suf = A::get_surface_mut(surface); unsafe { - suf.raw.unconfigure(&device.raw); + suf.unwrap().raw.unconfigure(&device.raw); //TODO: we could destroy the surface here } } @@ -1238,8 +1238,8 @@ pub trait HalApi: hal::Api { fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance; fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance>; fn hub(global: &Global) -> &Hub; - fn get_surface(surface: &Surface) -> &HalSurface; - fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface; + fn get_surface(surface: &Surface) -> Option<&HalSurface>; + fn get_surface_mut(surface: &mut Surface) -> Option<&mut HalSurface>; } impl HalApi for hal::api::Empty { @@ -1253,10 +1253,10 @@ impl HalApi for hal::api::Empty { fn hub(_: &Global) -> &Hub { unimplemented!("called empty api") } - fn get_surface(_: &Surface) -> &HalSurface { + fn get_surface(_: &Surface) -> Option<&HalSurface> { unimplemented!("called empty api") } - fn get_surface_mut(_: &mut Surface) -> &mut HalSurface { + fn get_surface_mut(_: &mut Surface) -> Option<&mut HalSurface> { unimplemented!("called empty api") } } @@ -1277,11 +1277,11 @@ impl HalApi for hal::api::Vulkan { fn hub(global: &Global) -> &Hub { &global.hubs.vulkan } - fn get_surface(surface: &Surface) -> &HalSurface { - surface.vulkan.as_ref().unwrap() + fn get_surface(surface: &Surface) -> Option<&HalSurface> { + surface.vulkan.as_ref() } - fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { - surface.vulkan.as_mut().unwrap() + fn get_surface_mut(surface: &mut Surface) -> Option<&mut HalSurface> { + surface.vulkan.as_mut() } } @@ -1301,11 +1301,11 @@ impl HalApi for hal::api::Metal { fn hub(global: &Global) -> &Hub { &global.hubs.metal } - fn get_surface(surface: &Surface) -> &HalSurface { - surface.metal.as_ref().unwrap() + fn get_surface(surface: &Surface) -> Option<&HalSurface> { + surface.metal.as_ref() } - fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { - surface.metal.as_mut().unwrap() + fn get_surface_mut(surface: &mut Surface) -> Option<&mut HalSurface> { + surface.metal.as_mut() } } @@ -1325,11 +1325,11 @@ impl HalApi for hal::api::Dx12 { fn hub(global: &Global) -> &Hub { &global.hubs.dx12 } - fn get_surface(surface: &Surface) -> &HalSurface { - surface.dx12.as_ref().unwrap() + fn get_surface(surface: &Surface) -> Option<&HalSurface> { + surface.dx12.as_ref() } - fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { - surface.dx12.as_mut().unwrap() + fn get_surface_mut(surface: &mut Surface) -> Option<&mut HalSurface> { + surface.dx12.as_mut() } } @@ -1349,11 +1349,11 @@ impl HalApi for hal::api::Dx11 { fn hub(global: &Global) -> &Hub { &global.hubs.dx11 } - fn get_surface(surface: &Surface) -> &HalSurface { - surface.dx11.as_ref().unwrap() + fn get_surface(surface: &Surface) -> Option<&HalSurface> { + surface.dx11.as_ref() } - fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { - surface.dx11.as_mut().unwrap() + fn get_surface_mut(surface: &mut Surface) -> Option<&mut HalSurface> { + surface.dx11.as_mut() } } @@ -1374,11 +1374,11 @@ impl HalApi for hal::api::Gles { fn hub(global: &Global) -> &Hub { &global.hubs.gl } - fn get_surface(surface: &Surface) -> &HalSurface { - surface.gl.as_ref().unwrap() + fn get_surface(surface: &Surface) -> Option<&HalSurface> { + surface.gl.as_ref() } - fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { - surface.gl.as_mut().unwrap() + fn get_surface_mut(surface: &mut Surface) -> Option<&mut HalSurface> { + surface.gl.as_mut() } } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index f483c40925..e1e9831dc3 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -183,14 +183,14 @@ impl Surface { &self, adapter: &Adapter, ) -> Result { - let suf = A::get_surface(self); + let suf = A::get_surface(self).ok_or(GetSurfaceSupportError::Unsupported)?; profiling::scope!("surface_capabilities"); let caps = unsafe { adapter .raw .adapter .surface_capabilities(&suf.raw) - .ok_or(GetSurfaceSupportError::UnsupportedQueueFamily)? + .ok_or(GetSurfaceSupportError::Unsupported)? }; Ok(caps) @@ -212,7 +212,15 @@ impl Adapter { pub fn is_surface_supported(&self, surface: &Surface) -> bool { let suf = A::get_surface(surface); - unsafe { self.raw.adapter.surface_capabilities(&suf.raw) }.is_some() + + // If get_surface returns None, then the API does not advertise support for the surface. + // + // This could occur if the user is running their app on Wayland but Vulkan does not support + // VK_KHR_wayland_surface. + match suf { + Some(suf) => unsafe { self.raw.adapter.surface_capabilities(&suf.raw) }.is_some(), + None => false, + } } pub(crate) fn get_texture_format_features( @@ -372,8 +380,8 @@ pub enum GetSurfaceSupportError { InvalidAdapter, #[error("invalid surface")] InvalidSurface, - #[error("surface does not support the adapter's queue family")] - UnsupportedQueueFamily, + #[error("surface is not supported by the adapter")] + Unsupported, } #[derive(Clone, Debug, Error)] @@ -721,9 +729,14 @@ impl Global { adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu); } if let Some(surface) = compatible_surface { - let suf_raw = &A::get_surface(surface).raw; + let surface = &A::get_surface(surface); adapters.retain(|exposed| unsafe { - exposed.adapter.surface_capabilities(suf_raw).is_some() + // If the surface does not exist for this backend, then the surface is not supported. + surface.is_some() + && exposed + .adapter + .surface_capabilities(&surface.unwrap().raw) + .is_some() }); } device_types.extend(adapters.iter().map(|ad| ad.info.device_type)); diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 250b136862..21047199ad 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -134,7 +134,8 @@ impl Global { let suf = A::get_surface_mut(surface); let (texture_id, status) = match unsafe { - suf.raw + suf.unwrap() + .raw .acquire_texture(Some(std::time::Duration::from_millis( FRAME_TIMEOUT_MS as u64, ))) @@ -311,10 +312,10 @@ impl Global { Err(hal::SurfaceError::Lost) } else if !has_work { log::error!("No work has been submitted for this frame"); - unsafe { suf.raw.discard_texture(raw) }; + unsafe { suf.unwrap().raw.discard_texture(raw) }; Err(hal::SurfaceError::Outdated) } else { - unsafe { device.queue.present(&mut suf.raw, raw) } + unsafe { device.queue.present(&mut suf.unwrap().raw, raw) } } } resource::TextureInner::Native { .. } => unreachable!(), @@ -387,7 +388,7 @@ impl Global { has_work: _, } => { if surface_id == parent_id.0 { - unsafe { suf.raw.discard_texture(raw) }; + unsafe { suf.unwrap().raw.discard_texture(raw) }; } else { log::warn!("Surface texture is outdated"); } diff --git a/wgpu-hal/src/gles/web.rs b/wgpu-hal/src/gles/web.rs index 396fdad04b..11eeb30d23 100644 --- a/wgpu-hal/src/gles/web.rs +++ b/wgpu-hal/src/gles/web.rs @@ -123,7 +123,7 @@ impl crate::Instance for Instance { self.create_surface_from_canvas(&canvas) } else { - unreachable!() + Err(crate::InstanceError) } } diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 79045ff061..55a8dec818 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -303,9 +303,10 @@ impl super::Instance { &self, dpy: *mut vk::Display, window: vk::Window, - ) -> super::Surface { + ) -> Result { if !self.shared.extensions.contains(&khr::XlibSurface::name()) { - panic!("Vulkan driver does not support VK_KHR_XLIB_SURFACE"); + log::warn!("Vulkan driver does not support VK_KHR_xlib_surface"); + return Err(crate::InstanceError); } let surface = { @@ -319,7 +320,7 @@ impl super::Instance { .expect("XlibSurface::create_xlib_surface() failed") }; - self.create_surface_from_vk_surface_khr(surface) + Ok(self.create_surface_from_vk_surface_khr(surface)) } #[allow(dead_code)] @@ -327,9 +328,10 @@ impl super::Instance { &self, connection: *mut vk::xcb_connection_t, window: vk::xcb_window_t, - ) -> super::Surface { + ) -> Result { if !self.shared.extensions.contains(&khr::XcbSurface::name()) { - panic!("Vulkan driver does not support VK_KHR_XCB_SURFACE"); + log::warn!("Vulkan driver does not support VK_KHR_xcb_surface"); + return Err(crate::InstanceError); } let surface = { @@ -343,7 +345,7 @@ impl super::Instance { .expect("XcbSurface::create_xcb_surface() failed") }; - self.create_surface_from_vk_surface_khr(surface) + Ok(self.create_surface_from_vk_surface_khr(surface)) } #[allow(dead_code)] @@ -351,13 +353,14 @@ impl super::Instance { &self, display: *mut c_void, surface: *mut c_void, - ) -> super::Surface { + ) -> Result { if !self .shared .extensions .contains(&khr::WaylandSurface::name()) { - panic!("Vulkan driver does not support VK_KHR_WAYLAND_SURFACE"); + log::debug!("Vulkan driver does not support VK_KHR_wayland_surface"); + return Err(crate::InstanceError); } let surface = { @@ -370,11 +373,23 @@ impl super::Instance { unsafe { w_loader.create_wayland_surface(&info, None) }.expect("WaylandSurface failed") }; - self.create_surface_from_vk_surface_khr(surface) + Ok(self.create_surface_from_vk_surface_khr(surface)) } #[allow(dead_code)] - fn create_surface_android(&self, window: *const c_void) -> super::Surface { + fn create_surface_android( + &self, + window: *const c_void, + ) -> Result { + if !self + .shared + .extensions + .contains(&khr::AndroidSurface::name()) + { + log::warn!("Vulkan driver does not support VK_KHR_android_surface"); + return Err(crate::InstanceError); + } + let surface = { let a_loader = khr::AndroidSurface::new(&self.shared.entry, &self.shared.raw); let info = vk::AndroidSurfaceCreateInfoKHR::builder() @@ -384,7 +399,7 @@ impl super::Instance { unsafe { a_loader.create_android_surface(&info, None) }.expect("AndroidSurface failed") }; - self.create_surface_from_vk_surface_khr(surface) + Ok(self.create_surface_from_vk_surface_khr(surface)) } #[allow(dead_code)] @@ -392,9 +407,10 @@ impl super::Instance { &self, hinstance: *mut c_void, hwnd: *mut c_void, - ) -> super::Surface { + ) -> Result { if !self.shared.extensions.contains(&khr::Win32Surface::name()) { - panic!("Vulkan driver does not support VK_KHR_WIN32_SURFACE"); + log::debug!("Vulkan driver does not support VK_KHR_win32_surface"); + return Err(crate::InstanceError); } let surface = { @@ -410,11 +426,19 @@ impl super::Instance { } }; - self.create_surface_from_vk_surface_khr(surface) + Ok(self.create_surface_from_vk_surface_khr(surface)) } #[cfg(any(target_os = "macos", target_os = "ios"))] - fn create_surface_from_view(&self, view: *mut c_void) -> super::Surface { + fn create_surface_from_view( + &self, + view: *mut c_void, + ) -> Result { + if !self.shared.extensions.contains(&ext::MetalSurface::name()) { + log::warn!("Vulkan driver does not support VK_EXT_metal_surface"); + return Err(crate::InstanceError); + } + let layer = unsafe { crate::metal::Surface::get_metal_layer(view as *mut objc::runtime::Object, None) }; @@ -429,7 +453,7 @@ impl super::Instance { unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() } }; - self.create_surface_from_vk_surface_khr(surface) + Ok(self.create_surface_from_vk_surface_khr(surface)) } fn create_surface_from_vk_surface_khr(&self, surface: vk::SurfaceKHR) -> super::Surface { @@ -598,37 +622,33 @@ impl crate::Instance for super::Instance { match (window_handle, display_handle) { (Rwh::Wayland(handle), Rdh::Wayland(display)) => { - Ok(self.create_surface_from_wayland(display.display, handle.surface)) + self.create_surface_from_wayland(display.display, handle.surface) } - (Rwh::Xlib(handle), Rdh::Xlib(display)) - if self.shared.extensions.contains(&khr::XlibSurface::name()) => - { - Ok(self.create_surface_from_xlib(display.display as *mut _, handle.window)) + (Rwh::Xlib(handle), Rdh::Xlib(display)) => { + self.create_surface_from_xlib(display.display as *mut _, handle.window) } - (Rwh::Xcb(handle), Rdh::Xcb(display)) - if self.shared.extensions.contains(&khr::XcbSurface::name()) => - { - Ok(self.create_surface_from_xcb(display.connection, handle.window)) + (Rwh::Xcb(handle), Rdh::Xcb(display)) => { + self.create_surface_from_xcb(display.connection, handle.window) } - (Rwh::AndroidNdk(handle), _) => Ok(self.create_surface_android(handle.a_native_window)), + (Rwh::AndroidNdk(handle), _) => self.create_surface_android(handle.a_native_window), #[cfg(windows)] (Rwh::Win32(handle), _) => { use winapi::um::libloaderapi::GetModuleHandleW; let hinstance = GetModuleHandleW(std::ptr::null()); - Ok(self.create_surface_from_hwnd(hinstance as *mut _, handle.hwnd)) + self.create_surface_from_hwnd(hinstance as *mut _, handle.hwnd) } #[cfg(target_os = "macos")] (Rwh::AppKit(handle), _) if self.shared.extensions.contains(&ext::MetalSurface::name()) => { - Ok(self.create_surface_from_view(handle.ns_view)) + self.create_surface_from_view(handle.ns_view) } #[cfg(target_os = "ios")] (Rwh::UiKit(handle), _) if self.shared.extensions.contains(&ext::MetalSurface::name()) => { - Ok(self.create_surface_from_view(handle.ui_view)) + self.create_surface_from_view(handle.ui_view) } (_, _) => Err(crate::InstanceError), } diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 8ec8bc6f66..8b4e3e8b76 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -969,7 +969,7 @@ impl crate::Context for Context { match wgc::gfx_select!(adapter => global.surface_get_supported_formats(surface.id, *adapter)) { Ok(formats) => formats, - Err(wgc::instance::GetSurfaceSupportError::UnsupportedQueueFamily) => vec![], + Err(wgc::instance::GetSurfaceSupportError::Unsupported) => vec![], Err(err) => self.handle_error_fatal(err, "Surface::get_supported_formats"), } } @@ -983,7 +983,7 @@ impl crate::Context for Context { match wgc::gfx_select!(adapter => global.surface_get_supported_present_modes(surface.id, *adapter)) { Ok(modes) => modes, - Err(wgc::instance::GetSurfaceSupportError::UnsupportedQueueFamily) => vec![], + Err(wgc::instance::GetSurfaceSupportError::Unsupported) => vec![], Err(err) => self.handle_error_fatal(err, "Surface::get_supported_present_modes"), } } @@ -997,7 +997,7 @@ impl crate::Context for Context { match wgc::gfx_select!(adapter => global.surface_get_supported_alpha_modes(surface.id, *adapter)) { Ok(modes) => modes, - Err(wgc::instance::GetSurfaceSupportError::UnsupportedQueueFamily) => { + Err(wgc::instance::GetSurfaceSupportError::Unsupported) => { vec![CompositeAlphaMode::Opaque] } Err(err) => self.handle_error_fatal(err, "Surface::get_supported_alpha_modes"), diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 9bdcd9d32e..52a77aba11 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1813,6 +1813,9 @@ impl Instance { /// Creates a surface from a raw window handle. /// + /// If the specified display and window handle are not supported by any of the backends, then the surface + /// will not be supported by any adapters. + /// /// # Safety /// /// - Raw Window Handle must be a valid object to create a surface upon and