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