• 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 use crate::format::Format;
11 use crate::image::ImageUsage;
12 use std::iter::FromIterator;
13 
14 /// The capabilities of a surface when used by a physical device.
15 ///
16 /// You have to match these capabilities when you create a swapchain.
17 #[derive(Clone, Debug)]
18 pub struct Capabilities {
19     /// Minimum number of images that must be present in the swapchain.
20     pub min_image_count: u32,
21 
22     /// Maximum number of images that must be present in the swapchain, or `None` if there is no
23     /// maximum value. Note that "no maximum" doesn't mean that you can set a very high value, as
24     /// you may still get out of memory errors.
25     pub max_image_count: Option<u32>,
26 
27     /// The current dimensions of the surface. `None` means that the surface's dimensions will
28     /// depend on the dimensions of the swapchain that you are going to create.
29     pub current_extent: Option<[u32; 2]>,
30 
31     /// Minimum width and height of a swapchain that uses this surface.
32     pub min_image_extent: [u32; 2],
33 
34     /// Maximum width and height of a swapchain that uses this surface.
35     pub max_image_extent: [u32; 2],
36 
37     /// Maximum number of image layers if you create an image array. The minimum is 1.
38     pub max_image_array_layers: u32,
39 
40     /// List of transforms supported for the swapchain.
41     pub supported_transforms: SupportedSurfaceTransforms,
42 
43     /// Current transform used by the surface.
44     pub current_transform: SurfaceTransform,
45 
46     /// List of composite alpha modes supports for the swapchain.
47     pub supported_composite_alpha: SupportedCompositeAlpha,
48 
49     /// List of image usages that are supported for images of the swapchain. Only
50     /// the `color_attachment` usage is guaranteed to be supported.
51     pub supported_usage_flags: ImageUsage,
52 
53     /// List of formats supported for the swapchain.
54     pub supported_formats: Vec<(Format, ColorSpace)>, // TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/207
55 
56     /// List of present modes that are supported. `Fifo` is always guaranteed to be supported.
57     pub present_modes: SupportedPresentModes,
58 }
59 
60 /// The way presenting a swapchain is accomplished.
61 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
62 #[repr(i32)]
63 pub enum PresentMode {
64     /// Immediately shows the image to the user. May result in visible tearing.
65     Immediate = ash::vk::PresentModeKHR::IMMEDIATE.as_raw(),
66 
67     /// The action of presenting an image puts it in wait. When the next vertical blanking period
68     /// happens, the waiting image is effectively shown to the user. If an image is presented while
69     /// another one is waiting, it is replaced.
70     Mailbox = ash::vk::PresentModeKHR::MAILBOX.as_raw(),
71 
72     /// The action of presenting an image adds it to a queue of images. At each vertical blanking
73     /// period, the queue is popped and an image is presented.
74     ///
75     /// Guaranteed to be always supported.
76     ///
77     /// This is the equivalent of OpenGL's `SwapInterval` with a value of 1.
78     Fifo = ash::vk::PresentModeKHR::FIFO.as_raw(),
79 
80     /// Same as `Fifo`, except that if the queue was empty during the previous vertical blanking
81     /// period then it is equivalent to `Immediate`.
82     ///
83     /// This is the equivalent of OpenGL's `SwapInterval` with a value of -1.
84     Relaxed = ash::vk::PresentModeKHR::FIFO_RELAXED.as_raw(),
85     // TODO: These can't be enabled yet because they have to be used with shared present surfaces
86     // which vulkano doesnt support yet.
87     //SharedDemand = ash::vk::PresentModeKHR::SHARED_DEMAND_REFRESH,
88     //SharedContinuous = ash::vk::PresentModeKHR::SHARED_CONTINUOUS_REFRESH,
89 }
90 
91 impl From<PresentMode> for ash::vk::PresentModeKHR {
92     #[inline]
from(val: PresentMode) -> Self93     fn from(val: PresentMode) -> Self {
94         Self::from_raw(val as i32)
95     }
96 }
97 
98 /// List of `PresentMode`s that are supported.
99 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
100 pub struct SupportedPresentModes {
101     pub immediate: bool,
102     pub mailbox: bool,
103     pub fifo: bool,
104     pub relaxed: bool,
105     pub shared_demand: bool,
106     pub shared_continuous: bool,
107 }
108 
109 impl FromIterator<ash::vk::PresentModeKHR> for SupportedPresentModes {
from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = ash::vk::PresentModeKHR>,110     fn from_iter<T>(iter: T) -> Self
111     where
112         T: IntoIterator<Item = ash::vk::PresentModeKHR>,
113     {
114         let mut result = SupportedPresentModes::none();
115         for e in iter {
116             match e {
117                 ash::vk::PresentModeKHR::IMMEDIATE => result.immediate = true,
118                 ash::vk::PresentModeKHR::MAILBOX => result.mailbox = true,
119                 ash::vk::PresentModeKHR::FIFO => result.fifo = true,
120                 ash::vk::PresentModeKHR::FIFO_RELAXED => result.relaxed = true,
121                 ash::vk::PresentModeKHR::SHARED_DEMAND_REFRESH => result.shared_demand = true,
122                 ash::vk::PresentModeKHR::SHARED_CONTINUOUS_REFRESH => {
123                     result.shared_continuous = true
124                 }
125                 _ => {}
126             }
127         }
128         result
129     }
130 }
131 
132 impl SupportedPresentModes {
133     /// Builds a `SupportedPresentModes` with all fields set to false.
134     #[inline]
none() -> SupportedPresentModes135     pub fn none() -> SupportedPresentModes {
136         SupportedPresentModes {
137             immediate: false,
138             mailbox: false,
139             fifo: false,
140             relaxed: false,
141             shared_demand: false,
142             shared_continuous: false,
143         }
144     }
145 
146     /// Returns true if the given present mode is in this list of supported modes.
147     #[inline]
supports(&self, mode: PresentMode) -> bool148     pub fn supports(&self, mode: PresentMode) -> bool {
149         match mode {
150             PresentMode::Immediate => self.immediate,
151             PresentMode::Mailbox => self.mailbox,
152             PresentMode::Fifo => self.fifo,
153             PresentMode::Relaxed => self.relaxed,
154         }
155     }
156 
157     /// Returns an iterator to the list of supported present modes.
158     #[inline]
iter(&self) -> SupportedPresentModesIter159     pub fn iter(&self) -> SupportedPresentModesIter {
160         SupportedPresentModesIter(self.clone())
161     }
162 }
163 
164 /// Enumeration of the `PresentMode`s that are supported.
165 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
166 pub struct SupportedPresentModesIter(SupportedPresentModes);
167 
168 impl Iterator for SupportedPresentModesIter {
169     type Item = PresentMode;
170 
171     #[inline]
next(&mut self) -> Option<PresentMode>172     fn next(&mut self) -> Option<PresentMode> {
173         if self.0.immediate {
174             self.0.immediate = false;
175             return Some(PresentMode::Immediate);
176         }
177         if self.0.mailbox {
178             self.0.mailbox = false;
179             return Some(PresentMode::Mailbox);
180         }
181         if self.0.fifo {
182             self.0.fifo = false;
183             return Some(PresentMode::Fifo);
184         }
185         if self.0.relaxed {
186             self.0.relaxed = false;
187             return Some(PresentMode::Relaxed);
188         }
189         None
190     }
191 }
192 
193 /// A transformation to apply to the image before showing it on the screen.
194 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
195 #[repr(u32)]
196 pub enum SurfaceTransform {
197     /// Don't transform the image.
198     Identity = ash::vk::SurfaceTransformFlagsKHR::IDENTITY.as_raw(),
199     /// Rotate 90 degrees.
200     Rotate90 = ash::vk::SurfaceTransformFlagsKHR::ROTATE_90.as_raw(),
201     /// Rotate 180 degrees.
202     Rotate180 = ash::vk::SurfaceTransformFlagsKHR::ROTATE_180.as_raw(),
203     /// Rotate 270 degrees.
204     Rotate270 = ash::vk::SurfaceTransformFlagsKHR::ROTATE_270.as_raw(),
205     /// Mirror the image horizontally.
206     HorizontalMirror = ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR.as_raw(),
207     /// Mirror the image horizontally and rotate 90 degrees.
208     HorizontalMirrorRotate90 =
209         ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_90.as_raw(),
210     /// Mirror the image horizontally and rotate 180 degrees.
211     HorizontalMirrorRotate180 =
212         ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_180.as_raw(),
213     /// Mirror the image horizontally and rotate 270 degrees.
214     HorizontalMirrorRotate270 =
215         ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_270.as_raw(),
216     /// Let the operating system or driver implementation choose.
217     Inherit = ash::vk::SurfaceTransformFlagsKHR::INHERIT.as_raw(),
218 }
219 
220 impl From<SurfaceTransform> for ash::vk::SurfaceTransformFlagsKHR {
221     #[inline]
from(val: SurfaceTransform) -> Self222     fn from(val: SurfaceTransform) -> Self {
223         Self::from_raw(val as u32)
224     }
225 }
226 
227 /// How the alpha values of the pixels of the window are treated.
228 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
229 #[repr(u32)]
230 pub enum CompositeAlpha {
231     /// The alpha channel of the image is ignored. All the pixels are considered as if they have a
232     /// value of 1.0.
233     Opaque = ash::vk::CompositeAlphaFlagsKHR::OPAQUE.as_raw(),
234 
235     /// The alpha channel of the image is respected. The color channels are expected to have
236     /// already been multiplied by the alpha value.
237     PreMultiplied = ash::vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED.as_raw(),
238 
239     /// The alpha channel of the image is respected. The color channels will be multiplied by the
240     /// alpha value by the compositor before being added to what is behind.
241     PostMultiplied = ash::vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED.as_raw(),
242 
243     /// Let the operating system or driver implementation choose.
244     Inherit = ash::vk::CompositeAlphaFlagsKHR::INHERIT.as_raw(),
245 }
246 
247 impl From<CompositeAlpha> for ash::vk::CompositeAlphaFlagsKHR {
248     #[inline]
from(val: CompositeAlpha) -> Self249     fn from(val: CompositeAlpha) -> Self {
250         Self::from_raw(val as u32)
251     }
252 }
253 
254 /// List of supported composite alpha modes.
255 ///
256 /// See the docs of `CompositeAlpha`.
257 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
258 #[allow(missing_docs)]
259 pub struct SupportedCompositeAlpha {
260     pub opaque: bool,
261     pub pre_multiplied: bool,
262     pub post_multiplied: bool,
263     pub inherit: bool,
264 }
265 
266 impl From<ash::vk::CompositeAlphaFlagsKHR> for SupportedCompositeAlpha {
267     #[inline]
from(val: ash::vk::CompositeAlphaFlagsKHR) -> SupportedCompositeAlpha268     fn from(val: ash::vk::CompositeAlphaFlagsKHR) -> SupportedCompositeAlpha {
269         let mut result = SupportedCompositeAlpha::none();
270         if !(val & ash::vk::CompositeAlphaFlagsKHR::OPAQUE).is_empty() {
271             result.opaque = true;
272         }
273         if !(val & ash::vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED).is_empty() {
274             result.pre_multiplied = true;
275         }
276         if !(val & ash::vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED).is_empty() {
277             result.post_multiplied = true;
278         }
279         if !(val & ash::vk::CompositeAlphaFlagsKHR::INHERIT).is_empty() {
280             result.inherit = true;
281         }
282         result
283     }
284 }
285 
286 impl SupportedCompositeAlpha {
287     /// Builds a `SupportedCompositeAlpha` with all fields set to false.
288     #[inline]
none() -> SupportedCompositeAlpha289     pub fn none() -> SupportedCompositeAlpha {
290         SupportedCompositeAlpha {
291             opaque: false,
292             pre_multiplied: false,
293             post_multiplied: false,
294             inherit: false,
295         }
296     }
297 
298     /// Returns true if the given `CompositeAlpha` is in this list.
299     #[inline]
supports(&self, value: CompositeAlpha) -> bool300     pub fn supports(&self, value: CompositeAlpha) -> bool {
301         match value {
302             CompositeAlpha::Opaque => self.opaque,
303             CompositeAlpha::PreMultiplied => self.pre_multiplied,
304             CompositeAlpha::PostMultiplied => self.post_multiplied,
305             CompositeAlpha::Inherit => self.inherit,
306         }
307     }
308 
309     /// Returns an iterator to the list of supported composite alpha.
310     #[inline]
iter(&self) -> SupportedCompositeAlphaIter311     pub fn iter(&self) -> SupportedCompositeAlphaIter {
312         SupportedCompositeAlphaIter(self.clone())
313     }
314 }
315 
316 /// Enumeration of the `CompositeAlpha` that are supported.
317 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
318 pub struct SupportedCompositeAlphaIter(SupportedCompositeAlpha);
319 
320 impl Iterator for SupportedCompositeAlphaIter {
321     type Item = CompositeAlpha;
322 
323     #[inline]
next(&mut self) -> Option<CompositeAlpha>324     fn next(&mut self) -> Option<CompositeAlpha> {
325         if self.0.opaque {
326             self.0.opaque = false;
327             return Some(CompositeAlpha::Opaque);
328         }
329         if self.0.pre_multiplied {
330             self.0.pre_multiplied = false;
331             return Some(CompositeAlpha::PreMultiplied);
332         }
333         if self.0.post_multiplied {
334             self.0.post_multiplied = false;
335             return Some(CompositeAlpha::PostMultiplied);
336         }
337         if self.0.inherit {
338             self.0.inherit = false;
339             return Some(CompositeAlpha::Inherit);
340         }
341         None
342     }
343 }
344 
345 /// List of supported composite alpha modes.
346 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
347 pub struct SupportedSurfaceTransforms {
348     pub identity: bool,
349     pub rotate90: bool,
350     pub rotate180: bool,
351     pub rotate270: bool,
352     pub horizontal_mirror: bool,
353     pub horizontal_mirror_rotate90: bool,
354     pub horizontal_mirror_rotate180: bool,
355     pub horizontal_mirror_rotate270: bool,
356     pub inherit: bool,
357 }
358 
359 impl From<ash::vk::SurfaceTransformFlagsKHR> for SupportedSurfaceTransforms {
from(val: ash::vk::SurfaceTransformFlagsKHR) -> Self360     fn from(val: ash::vk::SurfaceTransformFlagsKHR) -> Self {
361         macro_rules! v {
362             ($val:expr, $out:ident, $e:expr, $f:ident) => {
363                 if !($val & $e).is_empty() {
364                     $out.$f = true;
365                 }
366             };
367         }
368 
369         let mut result = SupportedSurfaceTransforms::none();
370         v!(
371             val,
372             result,
373             ash::vk::SurfaceTransformFlagsKHR::IDENTITY,
374             identity
375         );
376         v!(
377             val,
378             result,
379             ash::vk::SurfaceTransformFlagsKHR::ROTATE_90,
380             rotate90
381         );
382         v!(
383             val,
384             result,
385             ash::vk::SurfaceTransformFlagsKHR::ROTATE_180,
386             rotate180
387         );
388         v!(
389             val,
390             result,
391             ash::vk::SurfaceTransformFlagsKHR::ROTATE_270,
392             rotate270
393         );
394         v!(
395             val,
396             result,
397             ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR,
398             horizontal_mirror
399         );
400         v!(
401             val,
402             result,
403             ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_90,
404             horizontal_mirror_rotate90
405         );
406         v!(
407             val,
408             result,
409             ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_180,
410             horizontal_mirror_rotate180
411         );
412         v!(
413             val,
414             result,
415             ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_270,
416             horizontal_mirror_rotate270
417         );
418         v!(
419             val,
420             result,
421             ash::vk::SurfaceTransformFlagsKHR::INHERIT,
422             inherit
423         );
424         result
425     }
426 }
427 
428 impl SupportedSurfaceTransforms {
429     /// Builds a `SupportedSurfaceTransforms` with all fields set to false.
430     #[inline]
none() -> SupportedSurfaceTransforms431     pub fn none() -> SupportedSurfaceTransforms {
432         SupportedSurfaceTransforms {
433             identity: false,
434             rotate90: false,
435             rotate180: false,
436             rotate270: false,
437             horizontal_mirror: false,
438             horizontal_mirror_rotate90: false,
439             horizontal_mirror_rotate180: false,
440             horizontal_mirror_rotate270: false,
441             inherit: false,
442         }
443     }
444 
445     /// Returns true if the given `SurfaceTransform` is in this list.
446     #[inline]
supports(&self, value: SurfaceTransform) -> bool447     pub fn supports(&self, value: SurfaceTransform) -> bool {
448         match value {
449             SurfaceTransform::Identity => self.identity,
450             SurfaceTransform::Rotate90 => self.rotate90,
451             SurfaceTransform::Rotate180 => self.rotate180,
452             SurfaceTransform::Rotate270 => self.rotate270,
453             SurfaceTransform::HorizontalMirror => self.horizontal_mirror,
454             SurfaceTransform::HorizontalMirrorRotate90 => self.horizontal_mirror_rotate90,
455             SurfaceTransform::HorizontalMirrorRotate180 => self.horizontal_mirror_rotate180,
456             SurfaceTransform::HorizontalMirrorRotate270 => self.horizontal_mirror_rotate270,
457             SurfaceTransform::Inherit => self.inherit,
458         }
459     }
460 
461     /// Returns an iterator to the list of supported composite alpha.
462     #[inline]
iter(&self) -> SupportedSurfaceTransformsIter463     pub fn iter(&self) -> SupportedSurfaceTransformsIter {
464         SupportedSurfaceTransformsIter(self.clone())
465     }
466 }
467 
468 /// Enumeration of the `SurfaceTransform` that are supported.
469 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
470 pub struct SupportedSurfaceTransformsIter(SupportedSurfaceTransforms);
471 
472 impl Iterator for SupportedSurfaceTransformsIter {
473     type Item = SurfaceTransform;
474 
475     #[inline]
next(&mut self) -> Option<SurfaceTransform>476     fn next(&mut self) -> Option<SurfaceTransform> {
477         if self.0.identity {
478             self.0.identity = false;
479             return Some(SurfaceTransform::Identity);
480         }
481         if self.0.rotate90 {
482             self.0.rotate90 = false;
483             return Some(SurfaceTransform::Rotate90);
484         }
485         if self.0.rotate180 {
486             self.0.rotate180 = false;
487             return Some(SurfaceTransform::Rotate180);
488         }
489         if self.0.rotate270 {
490             self.0.rotate270 = false;
491             return Some(SurfaceTransform::Rotate270);
492         }
493         if self.0.horizontal_mirror {
494             self.0.horizontal_mirror = false;
495             return Some(SurfaceTransform::HorizontalMirror);
496         }
497         if self.0.horizontal_mirror_rotate90 {
498             self.0.horizontal_mirror_rotate90 = false;
499             return Some(SurfaceTransform::HorizontalMirrorRotate90);
500         }
501         if self.0.horizontal_mirror_rotate180 {
502             self.0.horizontal_mirror_rotate180 = false;
503             return Some(SurfaceTransform::HorizontalMirrorRotate180);
504         }
505         if self.0.horizontal_mirror_rotate270 {
506             self.0.horizontal_mirror_rotate270 = false;
507             return Some(SurfaceTransform::HorizontalMirrorRotate270);
508         }
509         if self.0.inherit {
510             self.0.inherit = false;
511             return Some(SurfaceTransform::Inherit);
512         }
513         None
514     }
515 }
516 
517 impl Default for SurfaceTransform {
518     #[inline]
default() -> SurfaceTransform519     fn default() -> SurfaceTransform {
520         SurfaceTransform::Identity
521     }
522 }
523 
524 /// How the presentation engine should interpret the data.
525 ///
526 /// # A quick lesson about color spaces
527 ///
528 /// ## What is a color space?
529 ///
530 /// Each pixel of a monitor is made of three components: one red, one green, and one blue. In the
531 /// past, computers would simply send to the monitor the intensity of each of the three components.
532 ///
533 /// This proved to be problematic, because depending on the brand of the monitor the colors would
534 /// not exactly be the same. For example on some monitors, a value of `[1.0, 0.0, 0.0]` would be a
535 /// bit more orange than on others.
536 ///
537 /// In order to standardize this, there exist what are called *color spaces*: sRGB, AdobeRGB,
538 /// DCI-P3, scRGB, etc. When you manipulate RGB values in a specific color space, these values have
539 /// a precise absolute meaning in terms of color, that is the same across all systems and monitors.
540 ///
541 /// > **Note**: Color spaces are orthogonal to concept of RGB. *RGB* only indicates what is the
542 /// > representation of the data, but not how it is interpreted. You can think of this a bit like
543 /// > text encoding. An *RGB* value is a like a byte, in other words it is the medium by which
544 /// > values are communicated, and a *color space* is like a text encoding (eg. UTF-8), in other
545 /// > words it is the way the value should be interpreted.
546 ///
547 /// The most commonly used color space today is sRGB. Most monitors today use this color space,
548 /// and most images files are encoded in this color space.
549 ///
550 /// ## Pixel formats and linear vs non-linear
551 ///
552 /// In Vulkan all images have a specific format in which the data is stored. The data of an image
553 /// consists of pixels in RGB but contains no information about the color space (or lack thereof)
554 /// of these pixels. You are free to store them in whatever color space you want.
555 ///
556 /// But one big practical problem with color spaces is that they are sometimes not linear, and in
557 /// particular the popular sRGB color space is not linear. In a non-linear color space, a value of
558 /// `[0.6, 0.6, 0.6]` for example is **not** twice as bright as a value of `[0.3, 0.3, 0.3]`. This
559 /// is problematic, because operations such as taking the average of two colors or calculating the
560 /// lighting of a texture with a dot product are mathematically incorrect and will produce
561 /// incorrect colors.
562 ///
563 /// > **Note**: If the texture format has an alpha component, it is not affected by the color space
564 /// > and always behaves linearly.
565 ///
566 /// In order to solve this Vulkan also provides image formats with the `Srgb` suffix, which are
567 /// expected to contain RGB data in the sRGB color space. When you sample an image with such a
568 /// format from a shader, the implementation will automatically turn the pixel values into a linear
569 /// color space that is suitable for linear operations (such as additions or multiplications).
570 /// When you write to a framebuffer attachment with such a format, the implementation will
571 /// automatically perform the opposite conversion. These conversions are most of the time performed
572 /// by the hardware and incur no additional cost.
573 ///
574 /// ## Color space of the swapchain
575 ///
576 /// The color space that you specify when you create a swapchain is how the implementation will
577 /// interpret the raw data inside of the image.
578 ///
579 /// > **Note**: The implementation can choose to send the data in the swapchain image directly to
580 /// > the monitor, but it can also choose to write it in an intermediary buffer that is then read
581 /// > by the operating system or windowing system. Therefore the color space that the
582 /// > implementation supports is not necessarily the same as the one supported by the monitor.
583 ///
584 /// It is *your* job to ensure that the data in the swapchain image is in the color space
585 /// that is specified here, otherwise colors will be incorrect.
586 /// The implementation will never perform any additional automatic conversion after the colors have
587 /// been written to the swapchain image.
588 ///
589 /// # How do I handle this correctly?
590 ///
591 /// The easiest way to handle color spaces in a cross-platform program is:
592 ///
593 /// - Always request the `SrgbNonLinear` color space when creating the swapchain.
594 /// - Make sure that all your image files use the sRGB color space, and load them in images whose
595 ///   format has the `Srgb` suffix. Only use non-sRGB image formats for intermediary computations
596 ///   or to store non-color data.
597 /// - Swapchain images should have a format with the `Srgb` suffix.
598 ///
599 /// > **Note**: It is unclear whether the `SrgbNonLinear` color space is always supported by the
600 /// > the implementation or not. See <https://github.com/KhronosGroup/Vulkan-Docs/issues/442>.
601 ///
602 /// > **Note**: Lots of developers are confused by color spaces. You can sometimes find articles
603 /// > talking about gamma correction and suggestion to put your colors to the power 2.2 for
604 /// > example. These are all hacks and you should use the sRGB pixel formats instead.
605 ///
606 /// If you follow these three rules, then everything should render the same way on all platforms.
607 ///
608 /// Additionally you can try detect whether the implementation supports any additional color space
609 /// and perform a manual conversion to that color space from inside your shader.
610 ///
611 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
612 #[repr(i32)]
613 pub enum ColorSpace {
614     SrgbNonLinear = ash::vk::ColorSpaceKHR::SRGB_NONLINEAR.as_raw(),
615     DisplayP3NonLinear = ash::vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT.as_raw(),
616     ExtendedSrgbLinear = ash::vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT.as_raw(),
617     ExtendedSrgbNonLinear = ash::vk::ColorSpaceKHR::EXTENDED_SRGB_NONLINEAR_EXT.as_raw(),
618     DciP3Linear = ash::vk::ColorSpaceKHR::DCI_P3_LINEAR_EXT.as_raw(),
619     DciP3NonLinear = ash::vk::ColorSpaceKHR::DCI_P3_NONLINEAR_EXT.as_raw(),
620     Bt709Linear = ash::vk::ColorSpaceKHR::BT709_LINEAR_EXT.as_raw(),
621     Bt709NonLinear = ash::vk::ColorSpaceKHR::BT709_NONLINEAR_EXT.as_raw(),
622     Bt2020Linear = ash::vk::ColorSpaceKHR::BT2020_LINEAR_EXT.as_raw(),
623     Hdr10St2084 = ash::vk::ColorSpaceKHR::HDR10_ST2084_EXT.as_raw(),
624     DolbyVision = ash::vk::ColorSpaceKHR::DOLBYVISION_EXT.as_raw(),
625     Hdr10Hlg = ash::vk::ColorSpaceKHR::HDR10_HLG_EXT.as_raw(),
626     AdobeRgbLinear = ash::vk::ColorSpaceKHR::ADOBERGB_LINEAR_EXT.as_raw(),
627     AdobeRgbNonLinear = ash::vk::ColorSpaceKHR::ADOBERGB_NONLINEAR_EXT.as_raw(),
628     PassThrough = ash::vk::ColorSpaceKHR::PASS_THROUGH_EXT.as_raw(),
629     DisplayNative = ash::vk::ColorSpaceKHR::DISPLAY_NATIVE_AMD.as_raw(),
630 }
631 
632 impl From<ColorSpace> for ash::vk::ColorSpaceKHR {
633     #[inline]
from(val: ColorSpace) -> Self634     fn from(val: ColorSpace) -> Self {
635         Self::from_raw(val as i32)
636     }
637 }
638 
639 impl From<ash::vk::ColorSpaceKHR> for ColorSpace {
640     #[inline]
from(val: ash::vk::ColorSpaceKHR) -> Self641     fn from(val: ash::vk::ColorSpaceKHR) -> Self {
642         match val {
643             ash::vk::ColorSpaceKHR::SRGB_NONLINEAR => ColorSpace::SrgbNonLinear,
644             ash::vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT => ColorSpace::DisplayP3NonLinear,
645             ash::vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT => ColorSpace::ExtendedSrgbLinear,
646             ash::vk::ColorSpaceKHR::EXTENDED_SRGB_NONLINEAR_EXT => {
647                 ColorSpace::ExtendedSrgbNonLinear
648             }
649             ash::vk::ColorSpaceKHR::DCI_P3_LINEAR_EXT => ColorSpace::DciP3Linear,
650             ash::vk::ColorSpaceKHR::DCI_P3_NONLINEAR_EXT => ColorSpace::DciP3NonLinear,
651             ash::vk::ColorSpaceKHR::BT709_LINEAR_EXT => ColorSpace::Bt709Linear,
652             ash::vk::ColorSpaceKHR::BT709_NONLINEAR_EXT => ColorSpace::Bt709NonLinear,
653             ash::vk::ColorSpaceKHR::BT2020_LINEAR_EXT => ColorSpace::Bt2020Linear,
654             ash::vk::ColorSpaceKHR::HDR10_ST2084_EXT => ColorSpace::Hdr10St2084,
655             ash::vk::ColorSpaceKHR::DOLBYVISION_EXT => ColorSpace::DolbyVision,
656             ash::vk::ColorSpaceKHR::HDR10_HLG_EXT => ColorSpace::Hdr10Hlg,
657             ash::vk::ColorSpaceKHR::ADOBERGB_LINEAR_EXT => ColorSpace::AdobeRgbLinear,
658             ash::vk::ColorSpaceKHR::ADOBERGB_NONLINEAR_EXT => ColorSpace::AdobeRgbNonLinear,
659             ash::vk::ColorSpaceKHR::PASS_THROUGH_EXT => ColorSpace::PassThrough,
660             ash::vk::ColorSpaceKHR::DISPLAY_NATIVE_AMD => ColorSpace::DisplayNative,
661             _ => panic!("Wrong value for color space enum {:?}", val),
662         }
663     }
664 }
665