// Copyright (c) 2016 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. //! Link between Vulkan and a window and/or the screen. //! //! Before you can draw on the screen or a window, you have to create two objects: //! //! - Create a `Surface` object that represents the location where the image will show up (either //! a window or a monitor). //! - Create a `Swapchain` that uses that `Surface`. //! //! Creating a surface can be done with only an `Instance` object. However creating a swapchain //! requires a `Device` object. //! //! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like //! you would draw on any other image. //! //! # Surfaces //! //! A surface is an object that represents a location where to render. It can be created from an //! instance and either a window handle (in a platform-specific way) or a monitor. //! //! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the //! instance. See the `instance` module for more information about how to enable extensions. //! //! ## Creating a surface from a window //! //! There are 5 extensions that each allow you to create a surface from a type of window: //! //! - `VK_KHR_xlib_surface` //! - `VK_KHR_xcb_surface` //! - `VK_KHR_wayland_surface` //! - `VK_KHR_android_surface` //! - `VK_KHR_win32_surface` //! //! For example if you want to create a surface from an Android surface, you will have to enable //! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`. //! See the documentation of `Surface` for all the possible constructors. //! //! Trying to use one of these functions without enabling the proper extension will result in an //! error. //! //! **Note that the `Surface` object is potentially unsafe**. It is your responsibility to //! keep the window alive for at least as long as the surface exists. In many cases Surface //! may be able to do this for you, if you pass it ownership of your Window (or a //! reference-counting container for it). //! //! ### Example //! //! ```no_run //! use std::ptr; //! use vulkano::instance::Instance; //! use vulkano::instance::InstanceExtensions; //! use vulkano::swapchain::Surface; //! use vulkano::Version; //! //! let instance = { //! let extensions = InstanceExtensions { //! khr_surface: true, //! khr_win32_surface: true, // If you don't enable this, `from_hwnd` will fail. //! .. InstanceExtensions::none() //! }; //! //! match Instance::new(None, Version::V1_1, &extensions, None) { //! Ok(i) => i, //! Err(err) => panic!("Couldn't build instance: {:?}", err) //! } //! }; //! //! # use std::sync::Arc; //! # struct Window(*const u32); //! # impl Window { //! # fn hwnd(&self) -> *const u32 { self.0 } //! # } //! # //! # fn build_window() -> Arc { Arc::new(Window(ptr::null())) } //! let window = build_window(); // Third-party function, not provided by vulkano //! let _surface = unsafe { //! let hinstance: *const () = ptr::null(); // Windows-specific object //! Surface::from_hwnd(instance.clone(), hinstance, window.hwnd(), Arc::clone(&window)).unwrap() //! }; //! ``` //! //! ## Creating a surface from a monitor //! //! Currently no system provides the `VK_KHR_display` extension that contains this feature. //! This feature is still a work-in-progress in vulkano and will reside in the `display` module. //! //! # Swapchains //! //! A surface represents a location on the screen and can be created from an instance. Once you //! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device, //! and allocates the resources that will be used to display images on the screen. //! //! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in //! turn on the screen, one after another. More information below. //! //! Swapchains have several properties: //! //! - The number of images that will cycle on the screen. //! - The format of the images. //! - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions. //! - The usage of the images, similar to creating other images. //! - The queue families that are going to use the images, similar to creating other images. //! - An additional transformation (rotation or mirroring) to perform on the final output. //! - How the alpha of the final output will be interpreted. //! - How to perform the cycling between images in regard to vsync. //! //! You can query the supported values of all these properties with //! [`Surface::capabilities()]`](struct.Surface.html#method.capabilities). //! //! ## Creating a swapchain //! //! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension //! on the device (and not on the instance like `VK_KHR_surface`): //! //! ```no_run //! # use vulkano::device::DeviceExtensions; //! let ext = DeviceExtensions { //! khr_swapchain: true, //! .. DeviceExtensions::none() //! }; //! ``` //! //! Then, query the capabilities of the surface with //! [`Surface::capabilities()`](struct.Surface.html#method.capabilities) //! and choose which values you are going to use. //! //! ```no_run //! # use std::sync::Arc; //! # use vulkano::device::Device; //! # use vulkano::swapchain::Surface; //! # use std::cmp::{max, min}; //! # fn choose_caps(device: Arc, surface: Arc>) -> Result<(), Box> { //! let caps = surface.capabilities(device.physical_device())?; //! //! // Use the current window size or some fixed resolution. //! let dimensions = caps.current_extent.unwrap_or([640, 480]); //! //! // Try to use double-buffering. //! let buffers_count = match caps.max_image_count { //! None => max(2, caps.min_image_count), //! Some(limit) => min(max(2, caps.min_image_count), limit) //! }; //! //! // Preserve the current surface transform. //! let transform = caps.current_transform; //! //! // Use the first available format. //! let (format, color_space) = caps.supported_formats[0]; //! # Ok(()) //! # } //! ``` //! //! Then, call [`Swapchain::new()`](struct.Swapchain.html#method.new). //! //! ```no_run //! # use std::sync::Arc; //! # use vulkano::device::{Device, Queue}; //! # use vulkano::image::ImageUsage; //! # use vulkano::sync::SharingMode; //! # use vulkano::format::Format; //! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha, ColorSpace, FullscreenExclusive}; //! # fn create_swapchain( //! # device: Arc, surface: Arc>, present_queue: Arc, //! # buffers_count: u32, format: Format, dimensions: [u32; 2], //! # surface_transform: SurfaceTransform, composite_alpha: CompositeAlpha, //! # present_mode: PresentMode, fullscreen_exclusive: FullscreenExclusive //! # ) -> Result<(), Box> { //! // The created swapchain will be used as a color attachment for rendering. //! let usage = ImageUsage { //! color_attachment: true, //! .. ImageUsage::none() //! }; //! //! // Create the swapchain and its buffers. //! let (swapchain, buffers) = Swapchain::start( //! // Create the swapchain in this `device`'s memory. //! device, //! // The surface where the images will be presented. //! surface, //! ) //! // How many buffers to use in the swapchain. //! .num_images(buffers_count) //! // The format of the images. //! .format(format) //! // The size of each image. //! .dimensions(dimensions) //! // What the images are going to be used for. //! .usage(usage) //! // What transformation to use with the surface. //! .transform(surface_transform) //! // How to handle the alpha channel. //! .composite_alpha(composite_alpha) //! // How to present images. //! .present_mode(present_mode) //! // How to handle fullscreen exclusivity //! .fullscreen_exclusive(fullscreen_exclusive) //! .build()?; //! //! # Ok(()) //! # } //! ``` //! //! Creating a swapchain not only returns the swapchain object, but also all the images that belong //! to it. //! //! ## Acquiring and presenting images //! //! Once you created a swapchain and retrieved all the images that belong to it (see previous //! section), you can draw on it. This is done in three steps: //! //! - Call `swapchain::acquire_next_image`. This function will return the index of the image //! (within the list returned by `Swapchain::new`) that is available to draw, plus a future //! representing the moment when the GPU will gain access to that image. //! - Draw on that image just like you would draw to any other image (see the documentation of //! the `pipeline` module). You need to chain the draw after the future that was returned by //! `acquire_next_image`. //! - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell //! the implementation that you are finished drawing to the image and that it can queue a //! command to present the image on the screen after the draw operations are finished. //! //! ``` //! use vulkano::swapchain; //! use vulkano::sync::GpuFuture; //! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return; //! # let mut swapchain: ::std::sync::Arc> = return; //! // let mut (swapchain, images) = Swapchain::new(...); //! loop { //! # let mut command_buffer: ::vulkano::command_buffer::PrimaryAutoCommandBuffer<()> = return; //! let (image_num, suboptimal, acquire_future) //! = swapchain::acquire_next_image(swapchain.clone(), None).unwrap(); //! //! // The command_buffer contains the draw commands that modify the framebuffer //! // constructed from images[image_num] //! acquire_future //! .then_execute(queue.clone(), command_buffer).unwrap() //! .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) //! .then_signal_fence_and_flush().unwrap(); //! } //! ``` //! //! ## Recreating a swapchain //! //! In some situations, the swapchain will become invalid by itself. This includes for example when //! the window is resized (as the images of the swapchain will no longer match the window's) or, //! on Android, when the application went to the background and goes back to the foreground. //! //! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering //! to an image of that swapchain will not produce any error, but may or may not work. To continue //! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing //! as last parameter the old swapchain. //! //! //! ``` //! use vulkano::swapchain; //! use vulkano::swapchain::AcquireError; //! use vulkano::sync::GpuFuture; //! //! // let mut swapchain = Swapchain::new(...); //! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain<()>>, _) = return; //! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return; //! let mut recreate_swapchain = false; //! //! loop { //! if recreate_swapchain { //! swapchain = swapchain.0.recreate().dimensions([1024, 768]).build().unwrap(); //! recreate_swapchain = false; //! } //! //! let (ref swapchain, ref _images) = swapchain; //! //! let (index, suboptimal, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { //! Ok(r) => r, //! Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; }, //! Err(err) => panic!("{:?}", err) //! }; //! //! // ... //! //! let final_future = acq_future //! // .then_execute(...) //! .then_swapchain_present(queue.clone(), swapchain.clone(), index) //! .then_signal_fence_and_flush().unwrap(); // TODO: PresentError? //! //! if suboptimal { //! recreate_swapchain = true; //! } //! } //! ``` //! use std::sync::atomic::AtomicBool; pub use self::capabilities::Capabilities; pub use self::capabilities::ColorSpace; pub use self::capabilities::CompositeAlpha; pub use self::capabilities::PresentMode; pub use self::capabilities::SupportedCompositeAlpha; pub use self::capabilities::SupportedCompositeAlphaIter; pub use self::capabilities::SupportedPresentModes; pub use self::capabilities::SupportedPresentModesIter; pub use self::capabilities::SupportedSurfaceTransforms; pub use self::capabilities::SupportedSurfaceTransformsIter; pub use self::capabilities::SurfaceTransform; pub use self::present_region::PresentRegion; pub use self::present_region::RectangleLayer; pub use self::surface::CapabilitiesError; pub use self::surface::Surface; pub use self::surface::SurfaceCreationError; pub use self::swapchain::acquire_next_image; pub use self::swapchain::acquire_next_image_raw; pub use self::swapchain::present; pub use self::swapchain::present_incremental; pub use self::swapchain::AcquireError; pub use self::swapchain::AcquiredImage; pub use self::swapchain::FullscreenExclusive; pub use self::swapchain::FullscreenExclusiveError; pub use self::swapchain::PresentFuture; pub use self::swapchain::Swapchain; pub use self::swapchain::SwapchainAcquireFuture; pub use self::swapchain::SwapchainBuilder; pub use self::swapchain::SwapchainCreationError; mod capabilities; pub mod display; mod present_region; mod surface; mod swapchain; /// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain" /// flag. // TODO: use pub(crate) maybe? unsafe trait SurfaceSwapchainLock { fn flag(&self) -> &AtomicBool; }