blob: 2a6feca1670f754110ec0853742c646137180715 [file] [log] [blame]
// 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),
}
}
}