diff options
Diffstat (limited to 'src/swapchain/surface.rs')
-rw-r--r-- | src/swapchain/surface.rs | 856 |
1 files changed, 0 insertions, 856 deletions
diff --git a/src/swapchain/surface.rs b/src/swapchain/surface.rs deleted file mode 100644 index 9bf5fd8..0000000 --- a/src/swapchain/surface.rs +++ /dev/null @@ -1,856 +0,0 @@ -// 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!(), - } - } -} |