1 // Copyright (c) 2016 The vulkano developers 2 // Licensed under the Apache License, Version 2.0 3 // <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT 5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, 6 // at your option. All files in the project carrying such 7 // notice may not be copied, modified, or distributed except 8 // according to those terms. 9 10 //! Link between Vulkan and a window and/or the screen. 11 //! 12 //! Before you can draw on the screen or a window, you have to create two objects: 13 //! 14 //! - Create a `Surface` object that represents the location where the image will show up (either 15 //! a window or a monitor). 16 //! - Create a `Swapchain` that uses that `Surface`. 17 //! 18 //! Creating a surface can be done with only an `Instance` object. However creating a swapchain 19 //! requires a `Device` object. 20 //! 21 //! Once you have a swapchain, you can retrieve `Image` objects from it and draw to them just like 22 //! you would draw on any other image. 23 //! 24 //! # Surfaces 25 //! 26 //! A surface is an object that represents a location where to render. It can be created from an 27 //! instance and either a window handle (in a platform-specific way) or a monitor. 28 //! 29 //! In order to use surfaces, you will have to enable the `VK_KHR_surface` extension on the 30 //! instance. See the `instance` module for more information about how to enable extensions. 31 //! 32 //! ## Creating a surface from a window 33 //! 34 //! There are 5 extensions that each allow you to create a surface from a type of window: 35 //! 36 //! - `VK_KHR_xlib_surface` 37 //! - `VK_KHR_xcb_surface` 38 //! - `VK_KHR_wayland_surface` 39 //! - `VK_KHR_android_surface` 40 //! - `VK_KHR_win32_surface` 41 //! 42 //! For example if you want to create a surface from an Android surface, you will have to enable 43 //! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`. 44 //! See the documentation of `Surface` for all the possible constructors. 45 //! 46 //! Trying to use one of these functions without enabling the proper extension will result in an 47 //! error. 48 //! 49 //! **Note that the `Surface` object is potentially unsafe**. It is your responsibility to 50 //! keep the window alive for at least as long as the surface exists. In many cases Surface 51 //! may be able to do this for you, if you pass it ownership of your Window (or a 52 //! reference-counting container for it). 53 //! 54 //! ### Example 55 //! 56 //! ```no_run 57 //! use std::ptr; 58 //! use vulkano::instance::Instance; 59 //! use vulkano::instance::InstanceExtensions; 60 //! use vulkano::swapchain::Surface; 61 //! use vulkano::Version; 62 //! 63 //! let instance = { 64 //! let extensions = InstanceExtensions { 65 //! khr_surface: true, 66 //! khr_win32_surface: true, // If you don't enable this, `from_hwnd` will fail. 67 //! .. InstanceExtensions::none() 68 //! }; 69 //! 70 //! match Instance::new(None, Version::V1_1, &extensions, None) { 71 //! Ok(i) => i, 72 //! Err(err) => panic!("Couldn't build instance: {:?}", err) 73 //! } 74 //! }; 75 //! 76 //! # use std::sync::Arc; 77 //! # struct Window(*const u32); 78 //! # impl Window { 79 //! # fn hwnd(&self) -> *const u32 { self.0 } 80 //! # } 81 //! # 82 //! # fn build_window() -> Arc<Window> { Arc::new(Window(ptr::null())) } 83 //! let window = build_window(); // Third-party function, not provided by vulkano 84 //! let _surface = unsafe { 85 //! let hinstance: *const () = ptr::null(); // Windows-specific object 86 //! Surface::from_hwnd(instance.clone(), hinstance, window.hwnd(), Arc::clone(&window)).unwrap() 87 //! }; 88 //! ``` 89 //! 90 //! ## Creating a surface from a monitor 91 //! 92 //! Currently no system provides the `VK_KHR_display` extension that contains this feature. 93 //! This feature is still a work-in-progress in vulkano and will reside in the `display` module. 94 //! 95 //! # Swapchains 96 //! 97 //! A surface represents a location on the screen and can be created from an instance. Once you 98 //! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device, 99 //! and allocates the resources that will be used to display images on the screen. 100 //! 101 //! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in 102 //! turn on the screen, one after another. More information below. 103 //! 104 //! Swapchains have several properties: 105 //! 106 //! - The number of images that will cycle on the screen. 107 //! - The format of the images. 108 //! - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions. 109 //! - The usage of the images, similar to creating other images. 110 //! - The queue families that are going to use the images, similar to creating other images. 111 //! - An additional transformation (rotation or mirroring) to perform on the final output. 112 //! - How the alpha of the final output will be interpreted. 113 //! - How to perform the cycling between images in regard to vsync. 114 //! 115 //! You can query the supported values of all these properties with 116 //! [`Surface::capabilities()]`](struct.Surface.html#method.capabilities). 117 //! 118 //! ## Creating a swapchain 119 //! 120 //! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension 121 //! on the device (and not on the instance like `VK_KHR_surface`): 122 //! 123 //! ```no_run 124 //! # use vulkano::device::DeviceExtensions; 125 //! let ext = DeviceExtensions { 126 //! khr_swapchain: true, 127 //! .. DeviceExtensions::none() 128 //! }; 129 //! ``` 130 //! 131 //! Then, query the capabilities of the surface with 132 //! [`Surface::capabilities()`](struct.Surface.html#method.capabilities) 133 //! and choose which values you are going to use. 134 //! 135 //! ```no_run 136 //! # use std::sync::Arc; 137 //! # use vulkano::device::Device; 138 //! # use vulkano::swapchain::Surface; 139 //! # use std::cmp::{max, min}; 140 //! # fn choose_caps(device: Arc<Device>, surface: Arc<Surface<()>>) -> Result<(), Box<std::error::Error>> { 141 //! let caps = surface.capabilities(device.physical_device())?; 142 //! 143 //! // Use the current window size or some fixed resolution. 144 //! let dimensions = caps.current_extent.unwrap_or([640, 480]); 145 //! 146 //! // Try to use double-buffering. 147 //! let buffers_count = match caps.max_image_count { 148 //! None => max(2, caps.min_image_count), 149 //! Some(limit) => min(max(2, caps.min_image_count), limit) 150 //! }; 151 //! 152 //! // Preserve the current surface transform. 153 //! let transform = caps.current_transform; 154 //! 155 //! // Use the first available format. 156 //! let (format, color_space) = caps.supported_formats[0]; 157 //! # Ok(()) 158 //! # } 159 //! ``` 160 //! 161 //! Then, call [`Swapchain::new()`](struct.Swapchain.html#method.new). 162 //! 163 //! ```no_run 164 //! # use std::sync::Arc; 165 //! # use vulkano::device::{Device, Queue}; 166 //! # use vulkano::image::ImageUsage; 167 //! # use vulkano::sync::SharingMode; 168 //! # use vulkano::format::Format; 169 //! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha, ColorSpace, FullscreenExclusive}; 170 //! # fn create_swapchain( 171 //! # device: Arc<Device>, surface: Arc<Surface<()>>, present_queue: Arc<Queue>, 172 //! # buffers_count: u32, format: Format, dimensions: [u32; 2], 173 //! # surface_transform: SurfaceTransform, composite_alpha: CompositeAlpha, 174 //! # present_mode: PresentMode, fullscreen_exclusive: FullscreenExclusive 175 //! # ) -> Result<(), Box<dyn std::error::Error>> { 176 //! // The created swapchain will be used as a color attachment for rendering. 177 //! let usage = ImageUsage { 178 //! color_attachment: true, 179 //! .. ImageUsage::none() 180 //! }; 181 //! 182 //! // Create the swapchain and its buffers. 183 //! let (swapchain, buffers) = Swapchain::start( 184 //! // Create the swapchain in this `device`'s memory. 185 //! device, 186 //! // The surface where the images will be presented. 187 //! surface, 188 //! ) 189 //! // How many buffers to use in the swapchain. 190 //! .num_images(buffers_count) 191 //! // The format of the images. 192 //! .format(format) 193 //! // The size of each image. 194 //! .dimensions(dimensions) 195 //! // What the images are going to be used for. 196 //! .usage(usage) 197 //! // What transformation to use with the surface. 198 //! .transform(surface_transform) 199 //! // How to handle the alpha channel. 200 //! .composite_alpha(composite_alpha) 201 //! // How to present images. 202 //! .present_mode(present_mode) 203 //! // How to handle fullscreen exclusivity 204 //! .fullscreen_exclusive(fullscreen_exclusive) 205 //! .build()?; 206 //! 207 //! # Ok(()) 208 //! # } 209 //! ``` 210 //! 211 //! Creating a swapchain not only returns the swapchain object, but also all the images that belong 212 //! to it. 213 //! 214 //! ## Acquiring and presenting images 215 //! 216 //! Once you created a swapchain and retrieved all the images that belong to it (see previous 217 //! section), you can draw on it. This is done in three steps: 218 //! 219 //! - Call `swapchain::acquire_next_image`. This function will return the index of the image 220 //! (within the list returned by `Swapchain::new`) that is available to draw, plus a future 221 //! representing the moment when the GPU will gain access to that image. 222 //! - Draw on that image just like you would draw to any other image (see the documentation of 223 //! the `pipeline` module). You need to chain the draw after the future that was returned by 224 //! `acquire_next_image`. 225 //! - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell 226 //! the implementation that you are finished drawing to the image and that it can queue a 227 //! command to present the image on the screen after the draw operations are finished. 228 //! 229 //! ``` 230 //! use vulkano::swapchain; 231 //! use vulkano::sync::GpuFuture; 232 //! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return; 233 //! # let mut swapchain: ::std::sync::Arc<swapchain::Swapchain<()>> = return; 234 //! // let mut (swapchain, images) = Swapchain::new(...); 235 //! loop { 236 //! # let mut command_buffer: ::vulkano::command_buffer::PrimaryAutoCommandBuffer<()> = return; 237 //! let (image_num, suboptimal, acquire_future) 238 //! = swapchain::acquire_next_image(swapchain.clone(), None).unwrap(); 239 //! 240 //! // The command_buffer contains the draw commands that modify the framebuffer 241 //! // constructed from images[image_num] 242 //! acquire_future 243 //! .then_execute(queue.clone(), command_buffer).unwrap() 244 //! .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) 245 //! .then_signal_fence_and_flush().unwrap(); 246 //! } 247 //! ``` 248 //! 249 //! ## Recreating a swapchain 250 //! 251 //! In some situations, the swapchain will become invalid by itself. This includes for example when 252 //! the window is resized (as the images of the swapchain will no longer match the window's) or, 253 //! on Android, when the application went to the background and goes back to the foreground. 254 //! 255 //! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering 256 //! to an image of that swapchain will not produce any error, but may or may not work. To continue 257 //! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing 258 //! as last parameter the old swapchain. 259 //! 260 //! 261 //! ``` 262 //! use vulkano::swapchain; 263 //! use vulkano::swapchain::AcquireError; 264 //! use vulkano::sync::GpuFuture; 265 //! 266 //! // let mut swapchain = Swapchain::new(...); 267 //! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain<()>>, _) = return; 268 //! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return; 269 //! let mut recreate_swapchain = false; 270 //! 271 //! loop { 272 //! if recreate_swapchain { 273 //! swapchain = swapchain.0.recreate().dimensions([1024, 768]).build().unwrap(); 274 //! recreate_swapchain = false; 275 //! } 276 //! 277 //! let (ref swapchain, ref _images) = swapchain; 278 //! 279 //! let (index, suboptimal, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { 280 //! Ok(r) => r, 281 //! Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; }, 282 //! Err(err) => panic!("{:?}", err) 283 //! }; 284 //! 285 //! // ... 286 //! 287 //! let final_future = acq_future 288 //! // .then_execute(...) 289 //! .then_swapchain_present(queue.clone(), swapchain.clone(), index) 290 //! .then_signal_fence_and_flush().unwrap(); // TODO: PresentError? 291 //! 292 //! if suboptimal { 293 //! recreate_swapchain = true; 294 //! } 295 //! } 296 //! ``` 297 //! 298 299 use std::sync::atomic::AtomicBool; 300 301 pub use self::capabilities::Capabilities; 302 pub use self::capabilities::ColorSpace; 303 pub use self::capabilities::CompositeAlpha; 304 pub use self::capabilities::PresentMode; 305 pub use self::capabilities::SupportedCompositeAlpha; 306 pub use self::capabilities::SupportedCompositeAlphaIter; 307 pub use self::capabilities::SupportedPresentModes; 308 pub use self::capabilities::SupportedPresentModesIter; 309 pub use self::capabilities::SupportedSurfaceTransforms; 310 pub use self::capabilities::SupportedSurfaceTransformsIter; 311 pub use self::capabilities::SurfaceTransform; 312 pub use self::present_region::PresentRegion; 313 pub use self::present_region::RectangleLayer; 314 pub use self::surface::CapabilitiesError; 315 pub use self::surface::Surface; 316 pub use self::surface::SurfaceCreationError; 317 pub use self::swapchain::acquire_next_image; 318 pub use self::swapchain::acquire_next_image_raw; 319 pub use self::swapchain::present; 320 pub use self::swapchain::present_incremental; 321 pub use self::swapchain::AcquireError; 322 pub use self::swapchain::AcquiredImage; 323 pub use self::swapchain::FullscreenExclusive; 324 pub use self::swapchain::FullscreenExclusiveError; 325 pub use self::swapchain::PresentFuture; 326 pub use self::swapchain::Swapchain; 327 pub use self::swapchain::SwapchainAcquireFuture; 328 pub use self::swapchain::SwapchainBuilder; 329 pub use self::swapchain::SwapchainCreationError; 330 331 mod capabilities; 332 pub mod display; 333 mod present_region; 334 mod surface; 335 mod swapchain; 336 337 /// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain" 338 /// flag. 339 // TODO: use pub(crate) maybe? 340 unsafe trait SurfaceSwapchainLock { flag(&self) -> &AtomicBool341 fn flag(&self) -> &AtomicBool; 342 } 343