aboutsummaryrefslogtreecommitdiff
path: root/src/swapchain/capabilities.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/swapchain/capabilities.rs')
-rw-r--r--src/swapchain/capabilities.rs664
1 files changed, 664 insertions, 0 deletions
diff --git a/src/swapchain/capabilities.rs b/src/swapchain/capabilities.rs
new file mode 100644
index 0000000..2a6feca
--- /dev/null
+++ b/src/swapchain/capabilities.rs
@@ -0,0 +1,664 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::format::Format;
+use crate::image::ImageUsage;
+use std::iter::FromIterator;
+
+/// The capabilities of a surface when used by a physical device.
+///
+/// You have to match these capabilities when you create a swapchain.
+#[derive(Clone, Debug)]
+pub struct Capabilities {
+ /// Minimum number of images that must be present in the swapchain.
+ pub min_image_count: u32,
+
+ /// Maximum number of images that must be present in the swapchain, or `None` if there is no
+ /// maximum value. Note that "no maximum" doesn't mean that you can set a very high value, as
+ /// you may still get out of memory errors.
+ pub max_image_count: Option<u32>,
+
+ /// The current dimensions of the surface. `None` means that the surface's dimensions will
+ /// depend on the dimensions of the swapchain that you are going to create.
+ pub current_extent: Option<[u32; 2]>,
+
+ /// Minimum width and height of a swapchain that uses this surface.
+ pub min_image_extent: [u32; 2],
+
+ /// Maximum width and height of a swapchain that uses this surface.
+ pub max_image_extent: [u32; 2],
+
+ /// Maximum number of image layers if you create an image array. The minimum is 1.
+ pub max_image_array_layers: u32,
+
+ /// List of transforms supported for the swapchain.
+ pub supported_transforms: SupportedSurfaceTransforms,
+
+ /// Current transform used by the surface.
+ pub current_transform: SurfaceTransform,
+
+ /// List of composite alpha modes supports for the swapchain.
+ pub supported_composite_alpha: SupportedCompositeAlpha,
+
+ /// List of image usages that are supported for images of the swapchain. Only
+ /// the `color_attachment` usage is guaranteed to be supported.
+ pub supported_usage_flags: ImageUsage,
+
+ /// List of formats supported for the swapchain.
+ pub supported_formats: Vec<(Format, ColorSpace)>, // TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/207
+
+ /// List of present modes that are supported. `Fifo` is always guaranteed to be supported.
+ pub present_modes: SupportedPresentModes,
+}
+
+/// The way presenting a swapchain is accomplished.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[repr(i32)]
+pub enum PresentMode {
+ /// Immediately shows the image to the user. May result in visible tearing.
+ Immediate = ash::vk::PresentModeKHR::IMMEDIATE.as_raw(),
+
+ /// The action of presenting an image puts it in wait. When the next vertical blanking period
+ /// happens, the waiting image is effectively shown to the user. If an image is presented while
+ /// another one is waiting, it is replaced.
+ Mailbox = ash::vk::PresentModeKHR::MAILBOX.as_raw(),
+
+ /// The action of presenting an image adds it to a queue of images. At each vertical blanking
+ /// period, the queue is popped and an image is presented.
+ ///
+ /// Guaranteed to be always supported.
+ ///
+ /// This is the equivalent of OpenGL's `SwapInterval` with a value of 1.
+ Fifo = ash::vk::PresentModeKHR::FIFO.as_raw(),
+
+ /// Same as `Fifo`, except that if the queue was empty during the previous vertical blanking
+ /// period then it is equivalent to `Immediate`.
+ ///
+ /// This is the equivalent of OpenGL's `SwapInterval` with a value of -1.
+ Relaxed = ash::vk::PresentModeKHR::FIFO_RELAXED.as_raw(),
+ // TODO: These can't be enabled yet because they have to be used with shared present surfaces
+ // which vulkano doesnt support yet.
+ //SharedDemand = ash::vk::PresentModeKHR::SHARED_DEMAND_REFRESH,
+ //SharedContinuous = ash::vk::PresentModeKHR::SHARED_CONTINUOUS_REFRESH,
+}
+
+impl From<PresentMode> for ash::vk::PresentModeKHR {
+ #[inline]
+ fn from(val: PresentMode) -> Self {
+ Self::from_raw(val as i32)
+ }
+}
+
+/// List of `PresentMode`s that are supported.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct SupportedPresentModes {
+ pub immediate: bool,
+ pub mailbox: bool,
+ pub fifo: bool,
+ pub relaxed: bool,
+ pub shared_demand: bool,
+ pub shared_continuous: bool,
+}
+
+impl FromIterator<ash::vk::PresentModeKHR> for SupportedPresentModes {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = ash::vk::PresentModeKHR>,
+ {
+ let mut result = SupportedPresentModes::none();
+ for e in iter {
+ match e {
+ ash::vk::PresentModeKHR::IMMEDIATE => result.immediate = true,
+ ash::vk::PresentModeKHR::MAILBOX => result.mailbox = true,
+ ash::vk::PresentModeKHR::FIFO => result.fifo = true,
+ ash::vk::PresentModeKHR::FIFO_RELAXED => result.relaxed = true,
+ ash::vk::PresentModeKHR::SHARED_DEMAND_REFRESH => result.shared_demand = true,
+ ash::vk::PresentModeKHR::SHARED_CONTINUOUS_REFRESH => {
+ result.shared_continuous = true
+ }
+ _ => {}
+ }
+ }
+ result
+ }
+}
+
+impl SupportedPresentModes {
+ /// Builds a `SupportedPresentModes` with all fields set to false.
+ #[inline]
+ pub fn none() -> SupportedPresentModes {
+ SupportedPresentModes {
+ immediate: false,
+ mailbox: false,
+ fifo: false,
+ relaxed: false,
+ shared_demand: false,
+ shared_continuous: false,
+ }
+ }
+
+ /// Returns true if the given present mode is in this list of supported modes.
+ #[inline]
+ pub fn supports(&self, mode: PresentMode) -> bool {
+ match mode {
+ PresentMode::Immediate => self.immediate,
+ PresentMode::Mailbox => self.mailbox,
+ PresentMode::Fifo => self.fifo,
+ PresentMode::Relaxed => self.relaxed,
+ }
+ }
+
+ /// Returns an iterator to the list of supported present modes.
+ #[inline]
+ pub fn iter(&self) -> SupportedPresentModesIter {
+ SupportedPresentModesIter(self.clone())
+ }
+}
+
+/// Enumeration of the `PresentMode`s that are supported.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct SupportedPresentModesIter(SupportedPresentModes);
+
+impl Iterator for SupportedPresentModesIter {
+ type Item = PresentMode;
+
+ #[inline]
+ fn next(&mut self) -> Option<PresentMode> {
+ if self.0.immediate {
+ self.0.immediate = false;
+ return Some(PresentMode::Immediate);
+ }
+ if self.0.mailbox {
+ self.0.mailbox = false;
+ return Some(PresentMode::Mailbox);
+ }
+ if self.0.fifo {
+ self.0.fifo = false;
+ return Some(PresentMode::Fifo);
+ }
+ if self.0.relaxed {
+ self.0.relaxed = false;
+ return Some(PresentMode::Relaxed);
+ }
+ None
+ }
+}
+
+/// A transformation to apply to the image before showing it on the screen.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[repr(u32)]
+pub enum SurfaceTransform {
+ /// Don't transform the image.
+ Identity = ash::vk::SurfaceTransformFlagsKHR::IDENTITY.as_raw(),
+ /// Rotate 90 degrees.
+ Rotate90 = ash::vk::SurfaceTransformFlagsKHR::ROTATE_90.as_raw(),
+ /// Rotate 180 degrees.
+ Rotate180 = ash::vk::SurfaceTransformFlagsKHR::ROTATE_180.as_raw(),
+ /// Rotate 270 degrees.
+ Rotate270 = ash::vk::SurfaceTransformFlagsKHR::ROTATE_270.as_raw(),
+ /// Mirror the image horizontally.
+ HorizontalMirror = ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR.as_raw(),
+ /// Mirror the image horizontally and rotate 90 degrees.
+ HorizontalMirrorRotate90 =
+ ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_90.as_raw(),
+ /// Mirror the image horizontally and rotate 180 degrees.
+ HorizontalMirrorRotate180 =
+ ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_180.as_raw(),
+ /// Mirror the image horizontally and rotate 270 degrees.
+ HorizontalMirrorRotate270 =
+ ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_270.as_raw(),
+ /// Let the operating system or driver implementation choose.
+ Inherit = ash::vk::SurfaceTransformFlagsKHR::INHERIT.as_raw(),
+}
+
+impl From<SurfaceTransform> for ash::vk::SurfaceTransformFlagsKHR {
+ #[inline]
+ fn from(val: SurfaceTransform) -> Self {
+ Self::from_raw(val as u32)
+ }
+}
+
+/// How the alpha values of the pixels of the window are treated.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[repr(u32)]
+pub enum CompositeAlpha {
+ /// The alpha channel of the image is ignored. All the pixels are considered as if they have a
+ /// value of 1.0.
+ Opaque = ash::vk::CompositeAlphaFlagsKHR::OPAQUE.as_raw(),
+
+ /// The alpha channel of the image is respected. The color channels are expected to have
+ /// already been multiplied by the alpha value.
+ PreMultiplied = ash::vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED.as_raw(),
+
+ /// The alpha channel of the image is respected. The color channels will be multiplied by the
+ /// alpha value by the compositor before being added to what is behind.
+ PostMultiplied = ash::vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED.as_raw(),
+
+ /// Let the operating system or driver implementation choose.
+ Inherit = ash::vk::CompositeAlphaFlagsKHR::INHERIT.as_raw(),
+}
+
+impl From<CompositeAlpha> for ash::vk::CompositeAlphaFlagsKHR {
+ #[inline]
+ fn from(val: CompositeAlpha) -> Self {
+ Self::from_raw(val as u32)
+ }
+}
+
+/// List of supported composite alpha modes.
+///
+/// See the docs of `CompositeAlpha`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[allow(missing_docs)]
+pub struct SupportedCompositeAlpha {
+ pub opaque: bool,
+ pub pre_multiplied: bool,
+ pub post_multiplied: bool,
+ pub inherit: bool,
+}
+
+impl From<ash::vk::CompositeAlphaFlagsKHR> for SupportedCompositeAlpha {
+ #[inline]
+ fn from(val: ash::vk::CompositeAlphaFlagsKHR) -> SupportedCompositeAlpha {
+ let mut result = SupportedCompositeAlpha::none();
+ if !(val & ash::vk::CompositeAlphaFlagsKHR::OPAQUE).is_empty() {
+ result.opaque = true;
+ }
+ if !(val & ash::vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED).is_empty() {
+ result.pre_multiplied = true;
+ }
+ if !(val & ash::vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED).is_empty() {
+ result.post_multiplied = true;
+ }
+ if !(val & ash::vk::CompositeAlphaFlagsKHR::INHERIT).is_empty() {
+ result.inherit = true;
+ }
+ result
+ }
+}
+
+impl SupportedCompositeAlpha {
+ /// Builds a `SupportedCompositeAlpha` with all fields set to false.
+ #[inline]
+ pub fn none() -> SupportedCompositeAlpha {
+ SupportedCompositeAlpha {
+ opaque: false,
+ pre_multiplied: false,
+ post_multiplied: false,
+ inherit: false,
+ }
+ }
+
+ /// Returns true if the given `CompositeAlpha` is in this list.
+ #[inline]
+ pub fn supports(&self, value: CompositeAlpha) -> bool {
+ match value {
+ CompositeAlpha::Opaque => self.opaque,
+ CompositeAlpha::PreMultiplied => self.pre_multiplied,
+ CompositeAlpha::PostMultiplied => self.post_multiplied,
+ CompositeAlpha::Inherit => self.inherit,
+ }
+ }
+
+ /// Returns an iterator to the list of supported composite alpha.
+ #[inline]
+ pub fn iter(&self) -> SupportedCompositeAlphaIter {
+ SupportedCompositeAlphaIter(self.clone())
+ }
+}
+
+/// Enumeration of the `CompositeAlpha` that are supported.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct SupportedCompositeAlphaIter(SupportedCompositeAlpha);
+
+impl Iterator for SupportedCompositeAlphaIter {
+ type Item = CompositeAlpha;
+
+ #[inline]
+ fn next(&mut self) -> Option<CompositeAlpha> {
+ if self.0.opaque {
+ self.0.opaque = false;
+ return Some(CompositeAlpha::Opaque);
+ }
+ if self.0.pre_multiplied {
+ self.0.pre_multiplied = false;
+ return Some(CompositeAlpha::PreMultiplied);
+ }
+ if self.0.post_multiplied {
+ self.0.post_multiplied = false;
+ return Some(CompositeAlpha::PostMultiplied);
+ }
+ if self.0.inherit {
+ self.0.inherit = false;
+ return Some(CompositeAlpha::Inherit);
+ }
+ None
+ }
+}
+
+/// List of supported composite alpha modes.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct SupportedSurfaceTransforms {
+ pub identity: bool,
+ pub rotate90: bool,
+ pub rotate180: bool,
+ pub rotate270: bool,
+ pub horizontal_mirror: bool,
+ pub horizontal_mirror_rotate90: bool,
+ pub horizontal_mirror_rotate180: bool,
+ pub horizontal_mirror_rotate270: bool,
+ pub inherit: bool,
+}
+
+impl From<ash::vk::SurfaceTransformFlagsKHR> for SupportedSurfaceTransforms {
+ fn from(val: ash::vk::SurfaceTransformFlagsKHR) -> Self {
+ macro_rules! v {
+ ($val:expr, $out:ident, $e:expr, $f:ident) => {
+ if !($val & $e).is_empty() {
+ $out.$f = true;
+ }
+ };
+ }
+
+ let mut result = SupportedSurfaceTransforms::none();
+ v!(
+ val,
+ result,
+ ash::vk::SurfaceTransformFlagsKHR::IDENTITY,
+ identity
+ );
+ v!(
+ val,
+ result,
+ ash::vk::SurfaceTransformFlagsKHR::ROTATE_90,
+ rotate90
+ );
+ v!(
+ val,
+ result,
+ ash::vk::SurfaceTransformFlagsKHR::ROTATE_180,
+ rotate180
+ );
+ v!(
+ val,
+ result,
+ ash::vk::SurfaceTransformFlagsKHR::ROTATE_270,
+ rotate270
+ );
+ v!(
+ val,
+ result,
+ ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR,
+ horizontal_mirror
+ );
+ v!(
+ val,
+ result,
+ ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_90,
+ horizontal_mirror_rotate90
+ );
+ v!(
+ val,
+ result,
+ ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_180,
+ horizontal_mirror_rotate180
+ );
+ v!(
+ val,
+ result,
+ ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_270,
+ horizontal_mirror_rotate270
+ );
+ v!(
+ val,
+ result,
+ ash::vk::SurfaceTransformFlagsKHR::INHERIT,
+ inherit
+ );
+ result
+ }
+}
+
+impl SupportedSurfaceTransforms {
+ /// Builds a `SupportedSurfaceTransforms` with all fields set to false.
+ #[inline]
+ pub fn none() -> SupportedSurfaceTransforms {
+ SupportedSurfaceTransforms {
+ identity: false,
+ rotate90: false,
+ rotate180: false,
+ rotate270: false,
+ horizontal_mirror: false,
+ horizontal_mirror_rotate90: false,
+ horizontal_mirror_rotate180: false,
+ horizontal_mirror_rotate270: false,
+ inherit: false,
+ }
+ }
+
+ /// Returns true if the given `SurfaceTransform` is in this list.
+ #[inline]
+ pub fn supports(&self, value: SurfaceTransform) -> bool {
+ match value {
+ SurfaceTransform::Identity => self.identity,
+ SurfaceTransform::Rotate90 => self.rotate90,
+ SurfaceTransform::Rotate180 => self.rotate180,
+ SurfaceTransform::Rotate270 => self.rotate270,
+ SurfaceTransform::HorizontalMirror => self.horizontal_mirror,
+ SurfaceTransform::HorizontalMirrorRotate90 => self.horizontal_mirror_rotate90,
+ SurfaceTransform::HorizontalMirrorRotate180 => self.horizontal_mirror_rotate180,
+ SurfaceTransform::HorizontalMirrorRotate270 => self.horizontal_mirror_rotate270,
+ SurfaceTransform::Inherit => self.inherit,
+ }
+ }
+
+ /// Returns an iterator to the list of supported composite alpha.
+ #[inline]
+ pub fn iter(&self) -> SupportedSurfaceTransformsIter {
+ SupportedSurfaceTransformsIter(self.clone())
+ }
+}
+
+/// Enumeration of the `SurfaceTransform` that are supported.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct SupportedSurfaceTransformsIter(SupportedSurfaceTransforms);
+
+impl Iterator for SupportedSurfaceTransformsIter {
+ type Item = SurfaceTransform;
+
+ #[inline]
+ fn next(&mut self) -> Option<SurfaceTransform> {
+ if self.0.identity {
+ self.0.identity = false;
+ return Some(SurfaceTransform::Identity);
+ }
+ if self.0.rotate90 {
+ self.0.rotate90 = false;
+ return Some(SurfaceTransform::Rotate90);
+ }
+ if self.0.rotate180 {
+ self.0.rotate180 = false;
+ return Some(SurfaceTransform::Rotate180);
+ }
+ if self.0.rotate270 {
+ self.0.rotate270 = false;
+ return Some(SurfaceTransform::Rotate270);
+ }
+ if self.0.horizontal_mirror {
+ self.0.horizontal_mirror = false;
+ return Some(SurfaceTransform::HorizontalMirror);
+ }
+ if self.0.horizontal_mirror_rotate90 {
+ self.0.horizontal_mirror_rotate90 = false;
+ return Some(SurfaceTransform::HorizontalMirrorRotate90);
+ }
+ if self.0.horizontal_mirror_rotate180 {
+ self.0.horizontal_mirror_rotate180 = false;
+ return Some(SurfaceTransform::HorizontalMirrorRotate180);
+ }
+ if self.0.horizontal_mirror_rotate270 {
+ self.0.horizontal_mirror_rotate270 = false;
+ return Some(SurfaceTransform::HorizontalMirrorRotate270);
+ }
+ if self.0.inherit {
+ self.0.inherit = false;
+ return Some(SurfaceTransform::Inherit);
+ }
+ None
+ }
+}
+
+impl Default for SurfaceTransform {
+ #[inline]
+ fn default() -> SurfaceTransform {
+ SurfaceTransform::Identity
+ }
+}
+
+/// How the presentation engine should interpret the data.
+///
+/// # A quick lesson about color spaces
+///
+/// ## What is a color space?
+///
+/// Each pixel of a monitor is made of three components: one red, one green, and one blue. In the
+/// past, computers would simply send to the monitor the intensity of each of the three components.
+///
+/// This proved to be problematic, because depending on the brand of the monitor the colors would
+/// not exactly be the same. For example on some monitors, a value of `[1.0, 0.0, 0.0]` would be a
+/// bit more orange than on others.
+///
+/// In order to standardize this, there exist what are called *color spaces*: sRGB, AdobeRGB,
+/// DCI-P3, scRGB, etc. When you manipulate RGB values in a specific color space, these values have
+/// a precise absolute meaning in terms of color, that is the same across all systems and monitors.
+///
+/// > **Note**: Color spaces are orthogonal to concept of RGB. *RGB* only indicates what is the
+/// > representation of the data, but not how it is interpreted. You can think of this a bit like
+/// > text encoding. An *RGB* value is a like a byte, in other words it is the medium by which
+/// > values are communicated, and a *color space* is like a text encoding (eg. UTF-8), in other
+/// > words it is the way the value should be interpreted.
+///
+/// The most commonly used color space today is sRGB. Most monitors today use this color space,
+/// and most images files are encoded in this color space.
+///
+/// ## Pixel formats and linear vs non-linear
+///
+/// In Vulkan all images have a specific format in which the data is stored. The data of an image
+/// consists of pixels in RGB but contains no information about the color space (or lack thereof)
+/// of these pixels. You are free to store them in whatever color space you want.
+///
+/// But one big practical problem with color spaces is that they are sometimes not linear, and in
+/// particular the popular sRGB color space is not linear. In a non-linear color space, a value of
+/// `[0.6, 0.6, 0.6]` for example is **not** twice as bright as a value of `[0.3, 0.3, 0.3]`. This
+/// is problematic, because operations such as taking the average of two colors or calculating the
+/// lighting of a texture with a dot product are mathematically incorrect and will produce
+/// incorrect colors.
+///
+/// > **Note**: If the texture format has an alpha component, it is not affected by the color space
+/// > and always behaves linearly.
+///
+/// In order to solve this Vulkan also provides image formats with the `Srgb` suffix, which are
+/// expected to contain RGB data in the sRGB color space. When you sample an image with such a
+/// format from a shader, the implementation will automatically turn the pixel values into a linear
+/// color space that is suitable for linear operations (such as additions or multiplications).
+/// When you write to a framebuffer attachment with such a format, the implementation will
+/// automatically perform the opposite conversion. These conversions are most of the time performed
+/// by the hardware and incur no additional cost.
+///
+/// ## Color space of the swapchain
+///
+/// The color space that you specify when you create a swapchain is how the implementation will
+/// interpret the raw data inside of the image.
+///
+/// > **Note**: The implementation can choose to send the data in the swapchain image directly to
+/// > the monitor, but it can also choose to write it in an intermediary buffer that is then read
+/// > by the operating system or windowing system. Therefore the color space that the
+/// > implementation supports is not necessarily the same as the one supported by the monitor.
+///
+/// It is *your* job to ensure that the data in the swapchain image is in the color space
+/// that is specified here, otherwise colors will be incorrect.
+/// The implementation will never perform any additional automatic conversion after the colors have
+/// been written to the swapchain image.
+///
+/// # How do I handle this correctly?
+///
+/// The easiest way to handle color spaces in a cross-platform program is:
+///
+/// - Always request the `SrgbNonLinear` color space when creating the swapchain.
+/// - Make sure that all your image files use the sRGB color space, and load them in images whose
+/// format has the `Srgb` suffix. Only use non-sRGB image formats for intermediary computations
+/// or to store non-color data.
+/// - Swapchain images should have a format with the `Srgb` suffix.
+///
+/// > **Note**: It is unclear whether the `SrgbNonLinear` color space is always supported by the
+/// > the implementation or not. See <https://github.com/KhronosGroup/Vulkan-Docs/issues/442>.
+///
+/// > **Note**: Lots of developers are confused by color spaces. You can sometimes find articles
+/// > talking about gamma correction and suggestion to put your colors to the power 2.2 for
+/// > example. These are all hacks and you should use the sRGB pixel formats instead.
+///
+/// If you follow these three rules, then everything should render the same way on all platforms.
+///
+/// Additionally you can try detect whether the implementation supports any additional color space
+/// and perform a manual conversion to that color space from inside your shader.
+///
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[repr(i32)]
+pub enum ColorSpace {
+ SrgbNonLinear = ash::vk::ColorSpaceKHR::SRGB_NONLINEAR.as_raw(),
+ DisplayP3NonLinear = ash::vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT.as_raw(),
+ ExtendedSrgbLinear = ash::vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT.as_raw(),
+ ExtendedSrgbNonLinear = ash::vk::ColorSpaceKHR::EXTENDED_SRGB_NONLINEAR_EXT.as_raw(),
+ DciP3Linear = ash::vk::ColorSpaceKHR::DCI_P3_LINEAR_EXT.as_raw(),
+ DciP3NonLinear = ash::vk::ColorSpaceKHR::DCI_P3_NONLINEAR_EXT.as_raw(),
+ Bt709Linear = ash::vk::ColorSpaceKHR::BT709_LINEAR_EXT.as_raw(),
+ Bt709NonLinear = ash::vk::ColorSpaceKHR::BT709_NONLINEAR_EXT.as_raw(),
+ Bt2020Linear = ash::vk::ColorSpaceKHR::BT2020_LINEAR_EXT.as_raw(),
+ Hdr10St2084 = ash::vk::ColorSpaceKHR::HDR10_ST2084_EXT.as_raw(),
+ DolbyVision = ash::vk::ColorSpaceKHR::DOLBYVISION_EXT.as_raw(),
+ Hdr10Hlg = ash::vk::ColorSpaceKHR::HDR10_HLG_EXT.as_raw(),
+ AdobeRgbLinear = ash::vk::ColorSpaceKHR::ADOBERGB_LINEAR_EXT.as_raw(),
+ AdobeRgbNonLinear = ash::vk::ColorSpaceKHR::ADOBERGB_NONLINEAR_EXT.as_raw(),
+ PassThrough = ash::vk::ColorSpaceKHR::PASS_THROUGH_EXT.as_raw(),
+ DisplayNative = ash::vk::ColorSpaceKHR::DISPLAY_NATIVE_AMD.as_raw(),
+}
+
+impl From<ColorSpace> for ash::vk::ColorSpaceKHR {
+ #[inline]
+ fn from(val: ColorSpace) -> Self {
+ Self::from_raw(val as i32)
+ }
+}
+
+impl From<ash::vk::ColorSpaceKHR> for ColorSpace {
+ #[inline]
+ fn from(val: ash::vk::ColorSpaceKHR) -> Self {
+ match val {
+ ash::vk::ColorSpaceKHR::SRGB_NONLINEAR => ColorSpace::SrgbNonLinear,
+ ash::vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT => ColorSpace::DisplayP3NonLinear,
+ ash::vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT => ColorSpace::ExtendedSrgbLinear,
+ ash::vk::ColorSpaceKHR::EXTENDED_SRGB_NONLINEAR_EXT => {
+ ColorSpace::ExtendedSrgbNonLinear
+ }
+ ash::vk::ColorSpaceKHR::DCI_P3_LINEAR_EXT => ColorSpace::DciP3Linear,
+ ash::vk::ColorSpaceKHR::DCI_P3_NONLINEAR_EXT => ColorSpace::DciP3NonLinear,
+ ash::vk::ColorSpaceKHR::BT709_LINEAR_EXT => ColorSpace::Bt709Linear,
+ ash::vk::ColorSpaceKHR::BT709_NONLINEAR_EXT => ColorSpace::Bt709NonLinear,
+ ash::vk::ColorSpaceKHR::BT2020_LINEAR_EXT => ColorSpace::Bt2020Linear,
+ ash::vk::ColorSpaceKHR::HDR10_ST2084_EXT => ColorSpace::Hdr10St2084,
+ ash::vk::ColorSpaceKHR::DOLBYVISION_EXT => ColorSpace::DolbyVision,
+ ash::vk::ColorSpaceKHR::HDR10_HLG_EXT => ColorSpace::Hdr10Hlg,
+ ash::vk::ColorSpaceKHR::ADOBERGB_LINEAR_EXT => ColorSpace::AdobeRgbLinear,
+ ash::vk::ColorSpaceKHR::ADOBERGB_NONLINEAR_EXT => ColorSpace::AdobeRgbNonLinear,
+ ash::vk::ColorSpaceKHR::PASS_THROUGH_EXT => ColorSpace::PassThrough,
+ ash::vk::ColorSpaceKHR::DISPLAY_NATIVE_AMD => ColorSpace::DisplayNative,
+ _ => panic!("Wrong value for color space enum {:?}", val),
+ }
+ }
+}