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_android`. 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 //! ### Examples 55 //! 56 //! ```no_run 57 //! use std::ptr; 58 //! use vulkano::{ 59 //! instance::{Instance, InstanceCreateInfo, InstanceExtensions}, 60 //! swapchain::Surface, 61 //! Version, VulkanLibrary, 62 //! }; 63 //! 64 //! let instance = { 65 //! let library = VulkanLibrary::new() 66 //! .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err)); 67 //! 68 //! let extensions = InstanceExtensions { 69 //! khr_surface: true, 70 //! khr_win32_surface: true, // If you don't enable this, `from_hwnd` will fail. 71 //! .. InstanceExtensions::empty() 72 //! }; 73 //! 74 //! Instance::new( 75 //! library, 76 //! InstanceCreateInfo { 77 //! enabled_extensions: extensions, 78 //! ..Default::default() 79 //! }, 80 //! ) 81 //! .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err)) 82 //! }; 83 //! 84 //! # use std::sync::Arc; 85 //! # struct Window(*const u32); 86 //! # impl Window { fn hwnd(&self) -> *const u32 { self.0 } } 87 //! # unsafe impl Send for Window {} 88 //! # unsafe impl Sync for Window {} 89 //! # fn build_window() -> Arc<Window> { Arc::new(Window(ptr::null())) } 90 //! let window = build_window(); // Third-party function, not provided by vulkano 91 //! let _surface = unsafe { 92 //! let hinstance: *const () = ptr::null(); // Windows-specific object 93 //! Surface::from_win32( 94 //! instance.clone(), 95 //! hinstance, window.hwnd(), 96 //! Some(window), 97 //! ).unwrap() 98 //! }; 99 //! ``` 100 //! 101 //! ## Creating a surface from a monitor 102 //! 103 //! Currently no system provides the `VK_KHR_display` extension that contains this feature. 104 //! This feature is still a work-in-progress in vulkano and will reside in the `display` module. 105 //! 106 //! # Swapchains 107 //! 108 //! A surface represents a location on the screen and can be created from an instance. Once you 109 //! have a surface, the next step is to create a swapchain. Creating a swapchain requires a device, 110 //! and allocates the resources that will be used to display images on the screen. 111 //! 112 //! A swapchain is composed of one or multiple images. Each image of the swapchain is presented in 113 //! turn on the screen, one after another. More information below. 114 //! 115 //! Swapchains have several properties: 116 //! 117 //! - The number of images that will cycle on the screen. 118 //! - The format of the images. 119 //! - The 2D dimensions of the images, plus a number of layers, for a total of three dimensions. 120 //! - The usage of the images, similar to creating other images. 121 //! - The queue families that are going to use the images, similar to creating other images. 122 //! - An additional transformation (rotation or mirroring) to perform on the final output. 123 //! - How the alpha of the final output will be interpreted. 124 //! - How to perform the cycling between images in regard to vsync. 125 //! 126 //! You can query the supported values of all these properties from the physical device. 127 //! 128 //! ## Creating a swapchain 129 //! 130 //! In order to create a swapchain, you will first have to enable the `VK_KHR_swapchain` extension 131 //! on the device (and not on the instance like `VK_KHR_surface`): 132 //! 133 //! ```no_run 134 //! # use vulkano::device::DeviceExtensions; 135 //! let ext = DeviceExtensions { 136 //! khr_swapchain: true, 137 //! .. DeviceExtensions::empty() 138 //! }; 139 //! ``` 140 //! 141 //! Then, query the capabilities of the surface with 142 //! [`PhysicalDevice::surface_capabilities`](crate::device::physical::PhysicalDevice::surface_capabilities) 143 //! and 144 //! [`PhysicalDevice::surface_formats`](crate::device::physical::PhysicalDevice::surface_formats) 145 //! and choose which values you are going to use. 146 //! 147 //! ```no_run 148 //! # use std::{error::Error, sync::Arc}; 149 //! # use vulkano::device::Device; 150 //! # use vulkano::swapchain::Surface; 151 //! # use std::cmp::{max, min}; 152 //! # fn choose_caps(device: Arc<Device>, surface: Arc<Surface>) -> Result<(), Box<dyn Error>> { 153 //! let surface_capabilities = device 154 //! .physical_device() 155 //! .surface_capabilities(&surface, Default::default())?; 156 //! 157 //! // Use the current window size or some fixed resolution. 158 //! let image_extent = surface_capabilities.current_extent.unwrap_or([640, 480]); 159 //! 160 //! // Try to use double-buffering. 161 //! let min_image_count = match surface_capabilities.max_image_count { 162 //! None => max(2, surface_capabilities.min_image_count), 163 //! Some(limit) => min(max(2, surface_capabilities.min_image_count), limit) 164 //! }; 165 //! 166 //! // Preserve the current surface transform. 167 //! let pre_transform = surface_capabilities.current_transform; 168 //! 169 //! // Use the first available format. 170 //! let (image_format, color_space) = device 171 //! .physical_device() 172 //! .surface_formats(&surface, Default::default())?[0]; 173 //! # Ok(()) 174 //! # } 175 //! ``` 176 //! 177 //! Then, call [`Swapchain::new`](crate::swapchain::Swapchain::new). 178 //! 179 //! ```no_run 180 //! # use std::{error::Error, sync::Arc}; 181 //! # use vulkano::device::{Device, Queue}; 182 //! # use vulkano::image::ImageUsage; 183 //! # use vulkano::sync::SharingMode; 184 //! # use vulkano::format::Format; 185 //! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha, ColorSpace, FullScreenExclusive, SwapchainCreateInfo}; 186 //! # fn create_swapchain( 187 //! # device: Arc<Device>, surface: Arc<Surface>, 188 //! # min_image_count: u32, image_format: Format, image_extent: [u32; 2], 189 //! # pre_transform: SurfaceTransform, composite_alpha: CompositeAlpha, 190 //! # present_mode: PresentMode, full_screen_exclusive: FullScreenExclusive 191 //! # ) -> Result<(), Box<dyn Error>> { 192 //! // Create the swapchain and its images. 193 //! let (swapchain, images) = Swapchain::new( 194 //! // Create the swapchain in this `device`'s memory. 195 //! device, 196 //! // The surface where the images will be presented. 197 //! surface, 198 //! // The creation parameters. 199 //! SwapchainCreateInfo { 200 //! // How many images to use in the swapchain. 201 //! min_image_count, 202 //! // The format of the images. 203 //! image_format: Some(image_format), 204 //! // The size of each image. 205 //! image_extent, 206 //! // The created swapchain images will be used as a color attachment for rendering. 207 //! image_usage: ImageUsage::COLOR_ATTACHMENT, 208 //! // What transformation to use with the surface. 209 //! pre_transform, 210 //! // How to handle the alpha channel. 211 //! composite_alpha, 212 //! // How to present images. 213 //! present_mode, 214 //! // How to handle full-screen exclusivity 215 //! full_screen_exclusive, 216 //! ..Default::default() 217 //! } 218 //! )?; 219 //! 220 //! # Ok(()) 221 //! # } 222 //! ``` 223 //! 224 //! Creating a swapchain not only returns the swapchain object, but also all the images that belong 225 //! to it. 226 //! 227 //! ## Acquiring and presenting images 228 //! 229 //! Once you created a swapchain and retrieved all the images that belong to it (see previous 230 //! section), you can draw on it. This is done in three steps: 231 //! 232 //! - Call `swapchain::acquire_next_image`. This function will return the index of the image 233 //! (within the list returned by `Swapchain::new`) that is available to draw, plus a future 234 //! representing the moment when the GPU will gain access to that image. 235 //! - Draw on that image just like you would draw to any other image (see the documentation of 236 //! the `pipeline` module). You need to chain the draw after the future that was returned by 237 //! `acquire_next_image`. 238 //! - Call `Swapchain::present` with the same index and by chaining the futures, in order to tell 239 //! the implementation that you are finished drawing to the image and that it can queue a 240 //! command to present the image on the screen after the draw operations are finished. 241 //! 242 //! ``` 243 //! use vulkano::swapchain::{self, SwapchainPresentInfo}; 244 //! use vulkano::sync::GpuFuture; 245 //! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return; 246 //! # let mut swapchain: ::std::sync::Arc<swapchain::Swapchain> = return; 247 //! // let mut (swapchain, images) = Swapchain::new(...); 248 //! loop { 249 //! # let mut command_buffer: ::vulkano::command_buffer::PrimaryAutoCommandBuffer = return; 250 //! let (image_index, suboptimal, acquire_future) 251 //! = swapchain::acquire_next_image(swapchain.clone(), None).unwrap(); 252 //! 253 //! // The command_buffer contains the draw commands that modify the framebuffer 254 //! // constructed from images[image_index] 255 //! acquire_future 256 //! .then_execute(queue.clone(), command_buffer) 257 //! .unwrap() 258 //! .then_swapchain_present( 259 //! queue.clone(), 260 //! SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), 261 //! ) 262 //! .then_signal_fence_and_flush() 263 //! .unwrap(); 264 //! } 265 //! ``` 266 //! 267 //! ## Recreating a swapchain 268 //! 269 //! In some situations, the swapchain will become invalid by itself. This includes for example when 270 //! the window is resized (as the images of the swapchain will no longer match the window's) or, 271 //! on Android, when the application went to the background and goes back to the foreground. 272 //! 273 //! In this situation, acquiring a swapchain image or presenting it will return an error. Rendering 274 //! to an image of that swapchain will not produce any error, but may or may not work. To continue 275 //! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing 276 //! as last parameter the old swapchain. 277 //! 278 //! ``` 279 //! use vulkano::swapchain; 280 //! use vulkano::swapchain::{AcquireError, SwapchainCreateInfo, SwapchainPresentInfo}; 281 //! use vulkano::sync::GpuFuture; 282 //! 283 //! // let (swapchain, images) = Swapchain::new(...); 284 //! # let mut swapchain: ::std::sync::Arc<::vulkano::swapchain::Swapchain> = return; 285 //! # let mut images: Vec<::std::sync::Arc<::vulkano::image::SwapchainImage>> = return; 286 //! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return; 287 //! let mut recreate_swapchain = false; 288 //! 289 //! loop { 290 //! if recreate_swapchain { 291 //! let (new_swapchain, new_images) = swapchain.recreate(SwapchainCreateInfo { 292 //! image_extent: [1024, 768], 293 //! ..swapchain.create_info() 294 //! }) 295 //! .unwrap(); 296 //! swapchain = new_swapchain; 297 //! images = new_images; 298 //! recreate_swapchain = false; 299 //! } 300 //! 301 //! let (image_index, suboptimal, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { 302 //! Ok(r) => r, 303 //! Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; }, 304 //! Err(err) => panic!("{:?}", err), 305 //! }; 306 //! 307 //! // ... 308 //! 309 //! let final_future = acq_future 310 //! // .then_execute(...) 311 //! .then_swapchain_present( 312 //! queue.clone(), 313 //! SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), 314 //! ) 315 //! .then_signal_fence_and_flush() 316 //! .unwrap(); // TODO: PresentError? 317 //! 318 //! if suboptimal { 319 //! recreate_swapchain = true; 320 //! } 321 //! } 322 //! ``` 323 324 pub use self::{ 325 surface::{ 326 ColorSpace, CompositeAlpha, CompositeAlphas, PresentMode, Surface, SurfaceApi, 327 SurfaceCapabilities, SurfaceCreationError, SurfaceInfo, SurfaceTransform, 328 SurfaceTransforms, 329 }, 330 swapchain::{ 331 acquire_next_image, acquire_next_image_raw, present, wait_for_present, AcquireError, 332 AcquiredImage, FullScreenExclusive, FullScreenExclusiveError, PresentFuture, 333 PresentWaitError, Swapchain, SwapchainAcquireFuture, SwapchainCreateInfo, 334 SwapchainCreationError, Win32Monitor, 335 }, 336 }; 337 #[cfg(target_os = "ios")] 338 pub use surface::IOSMetalLayer; 339 340 use crate::sync::semaphore::Semaphore; 341 use std::{ 342 num::NonZeroU64, 343 sync::{atomic::AtomicBool, Arc}, 344 }; 345 346 pub mod display; 347 mod surface; 348 mod swapchain; 349 350 /// Parameters to execute present operations on a queue. 351 #[derive(Clone, Debug)] 352 pub struct PresentInfo { 353 /// The semaphores to wait for before beginning the execution of the present operations. 354 /// 355 /// The default value is empty. 356 pub wait_semaphores: Vec<Arc<Semaphore>>, 357 358 /// The present operations to perform. 359 /// 360 /// The default value is empty. 361 pub swapchain_infos: Vec<SwapchainPresentInfo>, 362 363 pub _ne: crate::NonExhaustive, 364 } 365 366 impl Default for PresentInfo { 367 #[inline] default() -> Self368 fn default() -> Self { 369 Self { 370 wait_semaphores: Vec::new(), 371 swapchain_infos: Vec::new(), 372 _ne: crate::NonExhaustive(()), 373 } 374 } 375 } 376 377 /// Parameters for a single present operation on a swapchain. 378 #[derive(Clone, Debug)] 379 pub struct SwapchainPresentInfo { 380 /// The swapchain to present to. 381 /// 382 /// There is no default value. 383 pub swapchain: Arc<Swapchain>, 384 385 /// The index of the swapchain image to present to. 386 /// 387 /// The image must have been acquired first; this is the index that `acquire_next_image` 388 /// returns. 389 /// 390 /// There is no default value. 391 pub image_index: u32, 392 393 /// An id used to identify this present operation. 394 /// 395 /// If `present_id` is `Some`, the [`present_id`](crate::device::Features::present_id) feature 396 /// must be enabled on the device. The id must be greater than any id previously used for 397 /// `swapchain`. If a swapchain is recreated, this resets. 398 /// 399 /// The default value is `None`. 400 pub present_id: Option<NonZeroU64>, 401 402 /// Am optimization hint to the implementation, that only some parts of the swapchain image are 403 /// going to be updated by the present operation. 404 /// 405 /// If `present_regions` is not empty, the 406 /// [`khr_incremental_present`](crate::device::DeviceExtensions::khr_incremental_present) 407 /// extension must be enabled on the device. The implementation will update the provided 408 /// regions of the swapchain image, and _may_ ignore the other areas. However, as this is just 409 /// a hint, the Vulkan implementation is free to ignore the regions altogether and update 410 /// everything. 411 /// 412 /// If `present_regions` is empty, that means that all of the swapchain image must be updated. 413 /// 414 /// The default value is empty. 415 pub present_regions: Vec<RectangleLayer>, 416 417 pub _ne: crate::NonExhaustive, 418 } 419 420 impl SwapchainPresentInfo { 421 /// Returns a `SwapchainPresentInfo` with the specified `swapchain` and `image_index`. 422 #[inline] swapchain_image_index(swapchain: Arc<Swapchain>, image_index: u32) -> Self423 pub fn swapchain_image_index(swapchain: Arc<Swapchain>, image_index: u32) -> Self { 424 Self { 425 swapchain, 426 image_index, 427 present_id: None, 428 present_regions: Vec::new(), 429 _ne: crate::NonExhaustive(()), 430 } 431 } 432 } 433 434 /// Represents a rectangular region on an image layer. 435 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 436 pub struct RectangleLayer { 437 /// Coordinates in pixels of the top-left hand corner of the rectangle. 438 pub offset: [u32; 2], 439 440 /// Dimensions in pixels of the rectangle. 441 pub extent: [u32; 2], 442 443 /// The layer of the image. For images with only one layer, the value of layer must be 0. 444 pub layer: u32, 445 } 446 447 impl RectangleLayer { 448 /// Returns true if this rectangle layer is compatible with swapchain. 449 #[inline] is_compatible_with(&self, swapchain: &Swapchain) -> bool450 pub fn is_compatible_with(&self, swapchain: &Swapchain) -> bool { 451 self.offset[0] + self.extent[0] <= swapchain.image_extent()[0] 452 && self.offset[1] + self.extent[1] <= swapchain.image_extent()[1] 453 && self.layer < swapchain.image_array_layers() 454 } 455 } 456 457 impl From<&RectangleLayer> for ash::vk::RectLayerKHR { 458 #[inline] from(val: &RectangleLayer) -> Self459 fn from(val: &RectangleLayer) -> Self { 460 ash::vk::RectLayerKHR { 461 offset: ash::vk::Offset2D { 462 x: val.offset[0] as i32, 463 y: val.offset[1] as i32, 464 }, 465 extent: ash::vk::Extent2D { 466 width: val.extent[0], 467 height: val.extent[1], 468 }, 469 layer: val.layer, 470 } 471 } 472 } 473 474 /// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain" 475 /// flag. 476 // TODO: use pub(crate) maybe? 477 unsafe trait SurfaceSwapchainLock { flag(&self) -> &AtomicBool478 fn flag(&self) -> &AtomicBool; 479 } 480