• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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