aboutsummaryrefslogtreecommitdiff
path: root/src/swapchain/surface.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/swapchain/surface.rs')
-rw-r--r--src/swapchain/surface.rs856
1 files changed, 856 insertions, 0 deletions
diff --git a/src/swapchain/surface.rs b/src/swapchain/surface.rs
new file mode 100644
index 0000000..9bf5fd8
--- /dev/null
+++ b/src/swapchain/surface.rs
@@ -0,0 +1,856 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::check_errors;
+use crate::device::physical::PhysicalDevice;
+use crate::device::physical::QueueFamily;
+use crate::format::Format;
+use crate::image::ImageUsage;
+use crate::instance::Instance;
+use crate::swapchain::capabilities::SupportedSurfaceTransforms;
+use crate::swapchain::display::DisplayMode;
+use crate::swapchain::display::DisplayPlane;
+use crate::swapchain::Capabilities;
+use crate::swapchain::SurfaceSwapchainLock;
+use crate::Error;
+use crate::OomError;
+use crate::VulkanObject;
+use std::convert::TryFrom;
+use std::error;
+use std::fmt;
+use std::mem::MaybeUninit;
+use std::os::raw::c_ulong;
+use std::ptr;
+use std::sync::atomic::AtomicBool;
+use std::sync::Arc;
+
+/// Represents a surface on the screen.
+///
+/// Creating a `Surface` is platform-specific.
+pub struct Surface<W> {
+ window: W,
+ instance: Arc<Instance>,
+ surface: ash::vk::SurfaceKHR,
+
+ // If true, a swapchain has been associated to this surface, and that any new swapchain
+ // creation should be forbidden.
+ has_swapchain: AtomicBool,
+}
+
+impl<W> Surface<W> {
+ /// Creates a `Surface` given the raw handler.
+ ///
+ /// Be careful when using it
+ ///
+ pub unsafe fn from_raw_surface(
+ instance: Arc<Instance>,
+ surface: ash::vk::SurfaceKHR,
+ win: W,
+ ) -> Surface<W> {
+ Surface {
+ window: win,
+ instance,
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }
+ }
+
+ /// Creates a `Surface` that covers a display mode.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if `display_mode` and `plane` don't belong to the same physical device.
+ /// - Panics if `plane` doesn't support the display of `display_mode`.
+ ///
+ pub fn from_display_mode(
+ display_mode: &DisplayMode,
+ plane: &DisplayPlane,
+ ) -> Result<Arc<Surface<()>>, SurfaceCreationError> {
+ if !display_mode
+ .display()
+ .physical_device()
+ .instance()
+ .enabled_extensions()
+ .khr_display
+ {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_display",
+ });
+ }
+
+ assert_eq!(
+ display_mode.display().physical_device().internal_object(),
+ plane.physical_device().internal_object()
+ );
+ assert!(plane.supports(display_mode.display()));
+
+ let instance = display_mode.display().physical_device().instance();
+ let fns = instance.fns();
+
+ let surface = unsafe {
+ let infos = ash::vk::DisplaySurfaceCreateInfoKHR {
+ flags: ash::vk::DisplaySurfaceCreateFlagsKHR::empty(),
+ display_mode: display_mode.internal_object(),
+ plane_index: plane.index(),
+ plane_stack_index: 0, // FIXME: plane.properties.currentStackIndex,
+ transform: ash::vk::SurfaceTransformFlagsKHR::IDENTITY, // TODO: let user choose
+ global_alpha: 0.0, // TODO: let user choose
+ alpha_mode: ash::vk::DisplayPlaneAlphaFlagsKHR::OPAQUE, // TODO: let user choose
+ image_extent: ash::vk::Extent2D {
+ // TODO: let user choose
+ width: display_mode.visible_region()[0],
+ height: display_mode.visible_region()[1],
+ },
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_display.create_display_plane_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: (),
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from a Win32 window.
+ ///
+ /// The surface's min, max and current extent will always match the window's dimensions.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the `hinstance` and the `hwnd` are both correct and stay
+ /// alive for the entire lifetime of the surface. The `win` parameter can be used to ensure this.
+
+ pub unsafe fn from_hwnd<T, U>(
+ instance: Arc<Instance>,
+ hinstance: *const T,
+ hwnd: *const U,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_win32_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_win32_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::Win32SurfaceCreateInfoKHR {
+ flags: ash::vk::Win32SurfaceCreateFlagsKHR::empty(),
+ hinstance: hinstance as *mut _,
+ hwnd: hwnd as *mut _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_win32_surface.create_win32_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from an XCB window.
+ ///
+ /// The surface's min, max and current extent will always match the window's dimensions.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the `connection` and the `window` are both correct and stay
+ /// alive for the entire lifetime of the surface. The `win` parameter can be used to ensure this.
+ pub unsafe fn from_xcb<C>(
+ instance: Arc<Instance>,
+ connection: *const C,
+ window: u32,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_xcb_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_xcb_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::XcbSurfaceCreateInfoKHR {
+ flags: ash::vk::XcbSurfaceCreateFlagsKHR::empty(),
+ connection: connection as *mut _,
+ window,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_xcb_surface.create_xcb_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from an Xlib window.
+ ///
+ /// The surface's min, max and current extent will always match the window's dimensions.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the `display` and the `window` are both correct and stay
+ /// alive for the entire lifetime of the surface. The `win` parameter can be used to ensure this.
+ pub unsafe fn from_xlib<D>(
+ instance: Arc<Instance>,
+ display: *const D,
+ window: c_ulong,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_xlib_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_xlib_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::XlibSurfaceCreateInfoKHR {
+ flags: ash::vk::XlibSurfaceCreateFlagsKHR::empty(),
+ dpy: display as *mut _,
+ window,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_xlib_surface.create_xlib_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from a Wayland window.
+ ///
+ /// The window's dimensions will be set to the size of the swapchain.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the `display` and the `surface` are both correct and stay
+ /// alive for the entire lifetime of the surface. The `win` parameter can be used to ensure this.
+ pub unsafe fn from_wayland<D, S>(
+ instance: Arc<Instance>,
+ display: *const D,
+ surface: *const S,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_wayland_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_wayland_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::WaylandSurfaceCreateInfoKHR {
+ flags: ash::vk::WaylandSurfaceCreateFlagsKHR::empty(),
+ display: display as *mut _,
+ surface: surface as *mut _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_wayland_surface.create_wayland_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from an Android window.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the `window` is correct and stays alive for the entire
+ /// lifetime of the surface. The `win` parameter can be used to ensure this.
+ pub unsafe fn from_anativewindow<T>(
+ instance: Arc<Instance>,
+ window: *const T,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().khr_android_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_KHR_android_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::AndroidSurfaceCreateInfoKHR {
+ flags: ash::vk::AndroidSurfaceCreateFlagsKHR::empty(),
+ window: window as *mut _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_android_surface.create_android_surface_khr(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from an iOS `UIView`.
+ ///
+ /// # Safety
+ ///
+ /// - The caller must ensure that the `view` is correct and stays alive for the entire
+ /// lifetime of the surface. The win parameter can be used to ensure this.
+ /// - The `UIView` must be backed by a `CALayer` instance of type `CAMetalLayer`.
+ pub unsafe fn from_ios_moltenvk<T>(
+ instance: Arc<Instance>,
+ view: *const T,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().mvk_ios_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_MVK_ios_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::IOSSurfaceCreateInfoMVK {
+ flags: ash::vk::IOSSurfaceCreateFlagsMVK::empty(),
+ p_view: view as *const _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.mvk_ios_surface.create_ios_surface_mvk(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from a MacOS `NSView`.
+ ///
+ /// # Safety
+ ///
+ /// - The caller must ensure that the `view` is correct and stays alive for the entire
+ /// lifetime of the surface. The `win` parameter can be used to ensure this.
+ /// - The `NSView` must be backed by a `CALayer` instance of type `CAMetalLayer`.
+ pub unsafe fn from_macos_moltenvk<T>(
+ instance: Arc<Instance>,
+ view: *const T,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().mvk_macos_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_MVK_macos_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::MacOSSurfaceCreateInfoMVK {
+ flags: ash::vk::MacOSSurfaceCreateFlagsMVK::empty(),
+ p_view: view as *const _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.mvk_macos_surface.create_mac_os_surface_mvk(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Creates a `Surface` from a `code:nn::code:vi::code:Layer`.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the `window` is correct and stays alive for the entire
+ /// lifetime of the surface. The `win` parameter can be used to ensure this.
+ pub unsafe fn from_vi_surface<T>(
+ instance: Arc<Instance>,
+ window: *const T,
+ win: W,
+ ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
+ let fns = instance.fns();
+
+ if !instance.enabled_extensions().nn_vi_surface {
+ return Err(SurfaceCreationError::MissingExtension {
+ name: "VK_NN_vi_surface",
+ });
+ }
+
+ let surface = {
+ let infos = ash::vk::ViSurfaceCreateInfoNN {
+ flags: ash::vk::ViSurfaceCreateFlagsNN::empty(),
+ window: window as *mut _,
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.nn_vi_surface.create_vi_surface_nn(
+ instance.internal_object(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ ))?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Surface {
+ window: win,
+ instance: instance.clone(),
+ surface,
+ has_swapchain: AtomicBool::new(false),
+ }))
+ }
+
+ /// Returns true if the given queue family can draw on this surface.
+ // FIXME: vulkano doesn't check this for the moment!
+ pub fn is_supported(&self, queue: QueueFamily) -> Result<bool, CapabilitiesError> {
+ unsafe {
+ let fns = self.instance.fns();
+
+ let mut output = MaybeUninit::uninit();
+ check_errors(fns.khr_surface.get_physical_device_surface_support_khr(
+ queue.physical_device().internal_object(),
+ queue.id(),
+ self.surface,
+ output.as_mut_ptr(),
+ ))?;
+ Ok(output.assume_init() != 0)
+ }
+ }
+
+ /// Retrieves the capabilities of a surface when used by a certain device.
+ ///
+ /// # Notes
+ ///
+ /// - Capabilities that are not supported in `vk-sys` are silently dropped
+ ///
+ /// # Panic
+ ///
+ /// - Panics if the device and the surface don't belong to the same instance.
+ ///
+ pub fn capabilities(&self, device: PhysicalDevice) -> Result<Capabilities, CapabilitiesError> {
+ unsafe {
+ assert_eq!(
+ &*self.instance as *const _,
+ &**device.instance() as *const _,
+ "Instance mismatch in Surface::capabilities"
+ );
+
+ let fns = self.instance.fns();
+
+ let caps = {
+ let mut out: MaybeUninit<ash::vk::SurfaceCapabilitiesKHR> = MaybeUninit::uninit();
+ check_errors(
+ fns.khr_surface
+ .get_physical_device_surface_capabilities_khr(
+ device.internal_object(),
+ self.surface,
+ out.as_mut_ptr(),
+ ),
+ )?;
+ out.assume_init()
+ };
+
+ let formats = {
+ let mut num = 0;
+ check_errors(fns.khr_surface.get_physical_device_surface_formats_khr(
+ device.internal_object(),
+ self.surface,
+ &mut num,
+ ptr::null_mut(),
+ ))?;
+
+ let mut formats = Vec::with_capacity(num as usize);
+ check_errors(fns.khr_surface.get_physical_device_surface_formats_khr(
+ device.internal_object(),
+ self.surface,
+ &mut num,
+ formats.as_mut_ptr(),
+ ))?;
+ formats.set_len(num as usize);
+ formats
+ };
+
+ let modes = {
+ let mut num = 0;
+ check_errors(
+ fns.khr_surface
+ .get_physical_device_surface_present_modes_khr(
+ device.internal_object(),
+ self.surface,
+ &mut num,
+ ptr::null_mut(),
+ ),
+ )?;
+
+ let mut modes = Vec::with_capacity(num as usize);
+ check_errors(
+ fns.khr_surface
+ .get_physical_device_surface_present_modes_khr(
+ device.internal_object(),
+ self.surface,
+ &mut num,
+ modes.as_mut_ptr(),
+ ),
+ )?;
+ modes.set_len(num as usize);
+ debug_assert!(modes
+ .iter()
+ .find(|&&m| m == ash::vk::PresentModeKHR::FIFO)
+ .is_some());
+ debug_assert!(modes.iter().count() > 0);
+ modes.into_iter().collect()
+ };
+
+ Ok(Capabilities {
+ min_image_count: caps.min_image_count,
+ max_image_count: if caps.max_image_count == 0 {
+ None
+ } else {
+ Some(caps.max_image_count)
+ },
+ current_extent: if caps.current_extent.width == 0xffffffff
+ && caps.current_extent.height == 0xffffffff
+ {
+ None
+ } else {
+ Some([caps.current_extent.width, caps.current_extent.height])
+ },
+ min_image_extent: [caps.min_image_extent.width, caps.min_image_extent.height],
+ max_image_extent: [caps.max_image_extent.width, caps.max_image_extent.height],
+ max_image_array_layers: caps.max_image_array_layers,
+ supported_transforms: caps.supported_transforms.into(),
+
+ current_transform: SupportedSurfaceTransforms::from(caps.current_transform)
+ .iter()
+ .next()
+ .unwrap(), // TODO:
+ supported_composite_alpha: caps.supported_composite_alpha.into(),
+ supported_usage_flags: {
+ let usage = ImageUsage::from(caps.supported_usage_flags);
+ debug_assert!(usage.color_attachment); // specs say that this must be true
+ usage
+ },
+ supported_formats: formats
+ .into_iter()
+ .filter_map(|f| {
+ // TODO: Change the way capabilities not supported in vk-sys are handled
+ Format::try_from(f.format)
+ .ok()
+ .map(|format| (format, f.color_space.into()))
+ })
+ .collect(),
+ present_modes: modes,
+ })
+ }
+ }
+
+ #[inline]
+ pub fn window(&self) -> &W {
+ &self.window
+ }
+
+ /// Returns the instance this surface was created with.
+ #[inline]
+ pub fn instance(&self) -> &Arc<Instance> {
+ &self.instance
+ }
+}
+
+unsafe impl<W> SurfaceSwapchainLock for Surface<W> {
+ #[inline]
+ fn flag(&self) -> &AtomicBool {
+ &self.has_swapchain
+ }
+}
+
+unsafe impl<W> VulkanObject for Surface<W> {
+ type Object = ash::vk::SurfaceKHR;
+
+ #[inline]
+ fn internal_object(&self) -> ash::vk::SurfaceKHR {
+ self.surface
+ }
+}
+
+impl<W> fmt::Debug for Surface<W> {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(fmt, "<Vulkan surface {:?}>", self.surface)
+ }
+}
+
+impl<W> Drop for Surface<W> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.instance.fns();
+ fns.khr_surface.destroy_surface_khr(
+ self.instance.internal_object(),
+ self.surface,
+ ptr::null(),
+ );
+ }
+ }
+}
+
+/// Error that can happen when creating a debug callback.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum SurfaceCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ /// The extension required for this function was not enabled.
+ MissingExtension {
+ /// Name of the missing extension.
+ name: &'static str,
+ },
+}
+
+impl error::Error for SurfaceCreationError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ SurfaceCreationError::OomError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl fmt::Display for SurfaceCreationError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ match *self {
+ SurfaceCreationError::OomError(_) => "not enough memory available",
+ SurfaceCreationError::MissingExtension { .. } => {
+ "the extension required for this function was not enabled"
+ }
+ }
+ )
+ }
+}
+
+impl From<OomError> for SurfaceCreationError {
+ #[inline]
+ fn from(err: OomError) -> SurfaceCreationError {
+ SurfaceCreationError::OomError(err)
+ }
+}
+
+impl From<Error> for SurfaceCreationError {
+ #[inline]
+ fn from(err: Error) -> SurfaceCreationError {
+ match err {
+ err @ Error::OutOfHostMemory => SurfaceCreationError::OomError(OomError::from(err)),
+ err @ Error::OutOfDeviceMemory => SurfaceCreationError::OomError(OomError::from(err)),
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+/// Error that can happen when retrieving a surface's capabilities.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[repr(u32)]
+pub enum CapabilitiesError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ /// The surface is no longer accessible and must be recreated.
+ SurfaceLost,
+}
+
+impl error::Error for CapabilitiesError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ CapabilitiesError::OomError(ref err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl fmt::Display for CapabilitiesError {
+ #[inline]
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ write!(
+ fmt,
+ "{}",
+ match *self {
+ CapabilitiesError::OomError(_) => "not enough memory",
+ CapabilitiesError::SurfaceLost => "the surface is no longer valid",
+ }
+ )
+ }
+}
+
+impl From<OomError> for CapabilitiesError {
+ #[inline]
+ fn from(err: OomError) -> CapabilitiesError {
+ CapabilitiesError::OomError(err)
+ }
+}
+
+impl From<Error> for CapabilitiesError {
+ #[inline]
+ fn from(err: Error) -> CapabilitiesError {
+ match err {
+ err @ Error::OutOfHostMemory => CapabilitiesError::OomError(OomError::from(err)),
+ err @ Error::OutOfDeviceMemory => CapabilitiesError::OomError(OomError::from(err)),
+ Error::SurfaceLost => CapabilitiesError::SurfaceLost,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::swapchain::Surface;
+ use crate::swapchain::SurfaceCreationError;
+ use std::ptr;
+
+ #[test]
+ fn khr_win32_surface_ext_missing() {
+ let instance = instance!();
+ match unsafe { Surface::from_hwnd(instance, ptr::null::<u8>(), ptr::null::<u8>(), ()) } {
+ Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn khr_xcb_surface_ext_missing() {
+ let instance = instance!();
+ match unsafe { Surface::from_xcb(instance, ptr::null::<u8>(), 0, ()) } {
+ Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn khr_xlib_surface_ext_missing() {
+ let instance = instance!();
+ match unsafe { Surface::from_xlib(instance, ptr::null::<u8>(), 0, ()) } {
+ Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn khr_wayland_surface_ext_missing() {
+ let instance = instance!();
+ match unsafe { Surface::from_wayland(instance, ptr::null::<u8>(), ptr::null::<u8>(), ()) } {
+ Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn khr_android_surface_ext_missing() {
+ let instance = instance!();
+ match unsafe { Surface::from_anativewindow(instance, ptr::null::<u8>(), ()) } {
+ Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ _ => panic!(),
+ }
+ }
+}