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