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 //! Configures how the color output of the fragment shader is written to the attachment. 11 //! 12 //! # Blending in details 13 //! 14 //! There are three kinds of color attachments for the purpose of blending: 15 //! 16 //! - Attachments with a floating-point or fixed point format. 17 //! - Attachments with a (non-normalized) integer format. 18 //! - Attachments with a normalized integer format. 19 //! 20 //! For floating-point and fixed-point formats, the blending operation is applied. For integer 21 //! formats, the logic operation is applied. For normalized integer formats, the logic operation 22 //! will take precedence if it is activated, otherwise the blending operation is applied. 23 24 use crate::{ 25 macros::{vulkan_bitflags, vulkan_enum}, 26 pipeline::StateMode, 27 }; 28 29 /// Describes how the color output of the fragment shader is written to the attachment. See the 30 /// documentation of the `blend` module for more info. 31 #[derive(Clone, Debug)] 32 pub struct ColorBlendState { 33 /// Sets the logical operation to perform between the incoming fragment color and the existing 34 /// fragment in the framebuffer attachment. 35 /// 36 /// If set to `Some`, the [`logic_op`](crate::device::Features::logic_op) feature must be 37 /// enabled on the device. If set to `Some(Dynamic)`, then the 38 /// [`extended_dynamic_state2_logic_op`](crate::device::Features::extended_dynamic_state2_logic_op) 39 /// feature must also be enabled on the device. 40 pub logic_op: Option<StateMode<LogicOp>>, 41 42 /// Sets the blend and output state for each color attachment. The number of elements must match 43 /// the number of color attachments in the framebuffer. 44 /// 45 /// If there are multiple elements, and the `blend` and `color_write_mask` members of each 46 /// element differ, then the [`independent_blend`](crate::device::Features::independent_blend) 47 /// feature must be enabled on the device. 48 pub attachments: Vec<ColorBlendAttachmentState>, 49 50 /// The constant color to use for some of the `BlendFactor` variants. 51 pub blend_constants: StateMode<[f32; 4]>, 52 } 53 54 impl ColorBlendState { 55 /// Creates a `ColorBlendState` with logical operations disabled, blend constants set to zero, 56 /// and `num` attachment entries that have blending disabled, and color write and all color 57 /// components enabled. 58 #[inline] new(num: u32) -> Self59 pub fn new(num: u32) -> Self { 60 Self { 61 logic_op: None, 62 attachments: (0..num) 63 .map(|_| ColorBlendAttachmentState { 64 blend: None, 65 color_write_mask: ColorComponents::all(), 66 color_write_enable: StateMode::Fixed(true), 67 }) 68 .collect(), 69 blend_constants: StateMode::Fixed([0.0, 0.0, 0.0, 0.0]), 70 } 71 } 72 73 /// Enables logical operations with the given logical operation. 74 #[inline] logic_op(mut self, logic_op: LogicOp) -> Self75 pub fn logic_op(mut self, logic_op: LogicOp) -> Self { 76 self.logic_op = Some(StateMode::Fixed(logic_op)); 77 self 78 } 79 80 /// Enables logical operations with a dynamic logical operation. 81 #[inline] logic_op_dynamic(mut self) -> Self82 pub fn logic_op_dynamic(mut self) -> Self { 83 self.logic_op = Some(StateMode::Dynamic); 84 self 85 } 86 87 /// Enables blending for all attachments, with the given parameters. 88 #[inline] blend(mut self, blend: AttachmentBlend) -> Self89 pub fn blend(mut self, blend: AttachmentBlend) -> Self { 90 self.attachments 91 .iter_mut() 92 .for_each(|attachment_state| attachment_state.blend = Some(blend)); 93 self 94 } 95 96 /// Enables blending for all attachments, with alpha blending. 97 #[inline] blend_alpha(mut self) -> Self98 pub fn blend_alpha(mut self) -> Self { 99 self.attachments 100 .iter_mut() 101 .for_each(|attachment_state| attachment_state.blend = Some(AttachmentBlend::alpha())); 102 self 103 } 104 105 /// Enables blending for all attachments, with additive blending. 106 #[inline] blend_additive(mut self) -> Self107 pub fn blend_additive(mut self) -> Self { 108 self.attachments.iter_mut().for_each(|attachment_state| { 109 attachment_state.blend = Some(AttachmentBlend::additive()) 110 }); 111 self 112 } 113 114 /// Sets the color write mask for all attachments. 115 #[inline] color_write_mask(mut self, color_write_mask: ColorComponents) -> Self116 pub fn color_write_mask(mut self, color_write_mask: ColorComponents) -> Self { 117 self.attachments 118 .iter_mut() 119 .for_each(|attachment_state| attachment_state.color_write_mask = color_write_mask); 120 self 121 } 122 123 /// Sets the blend constants. 124 #[inline] blend_constants(mut self, constants: [f32; 4]) -> Self125 pub fn blend_constants(mut self, constants: [f32; 4]) -> Self { 126 self.blend_constants = StateMode::Fixed(constants); 127 self 128 } 129 130 /// Sets the blend constants as dynamic. 131 #[inline] blend_constants_dynamic(mut self) -> Self132 pub fn blend_constants_dynamic(mut self) -> Self { 133 self.blend_constants = StateMode::Dynamic; 134 self 135 } 136 } 137 138 impl Default for ColorBlendState { 139 /// Returns [`ColorBlendState::new(1)`]. 140 #[inline] default() -> Self141 fn default() -> Self { 142 Self::new(1) 143 } 144 } 145 146 vulkan_enum! { 147 #[non_exhaustive] 148 /// Which logical operation to apply to the output values. 149 /// 150 /// The operation is applied individually for each channel (red, green, blue and alpha). 151 /// 152 /// Only relevant for integer or unsigned attachments. 153 /// 154 /// Also note that some implementations don't support logic operations. 155 LogicOp = LogicOp(i32); 156 157 /// Returns `0`. 158 Clear = CLEAR, 159 160 /// Returns `source & destination`. 161 And = AND, 162 163 /// Returns `source & !destination`. 164 AndReverse = AND_REVERSE, 165 166 /// Returns `source`. 167 Copy = COPY, 168 169 /// Returns `!source & destination`. 170 AndInverted = AND_INVERTED, 171 172 /// Returns `destination`. 173 Noop = NO_OP, 174 175 /// Returns `source ^ destination`. 176 Xor = XOR, 177 178 /// Returns `source | destination`. 179 Or = OR, 180 181 /// Returns `!(source | destination)`. 182 Nor = NOR, 183 184 /// Returns `!(source ^ destination)`. 185 Equivalent = EQUIVALENT, 186 187 /// Returns `!destination`. 188 Invert = INVERT, 189 190 /// Returns `source | !destination. 191 OrReverse = OR_REVERSE, 192 193 /// Returns `!source`. 194 CopyInverted = COPY_INVERTED, 195 196 /// Returns `!source | destination`. 197 OrInverted = OR_INVERTED, 198 199 /// Returns `!(source & destination)`. 200 Nand = NAND, 201 202 /// Returns `!0` (all bits set to 1). 203 Set = SET, 204 205 } 206 207 impl Default for LogicOp { 208 #[inline] default() -> LogicOp209 fn default() -> LogicOp { 210 LogicOp::Noop 211 } 212 } 213 214 /// Describes how a framebuffer color attachment is handled in the pipeline during the color 215 /// blend stage. 216 #[derive(Clone, Debug)] 217 pub struct ColorBlendAttachmentState { 218 /// The blend parameters for the attachment. 219 /// 220 /// If set to `None`, blending is disabled, and all incoming pixels will be used directly. 221 pub blend: Option<AttachmentBlend>, 222 223 /// Sets which components of the final pixel value are written to the attachment. 224 pub color_write_mask: ColorComponents, 225 226 /// Sets whether anything at all is written to the attachment. If enabled, the pixel data 227 /// that is written is determined by the `color_write_mask`. If disabled, the mask is ignored 228 /// and nothing is written. 229 /// 230 /// If set to anything other than `Fixed(true)`, the 231 /// [`color_write_enable`](crate::device::Features::color_write_enable) feature must be enabled 232 /// on the device. 233 pub color_write_enable: StateMode<bool>, 234 } 235 236 /// Describes how the blending system should behave for an attachment. 237 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 238 pub struct AttachmentBlend { 239 /// The operation to apply between the color components of the source and destination pixels, 240 /// to produce the final pixel value. 241 pub color_op: BlendOp, 242 243 /// The operation to apply to the source color component before applying `color_op`. 244 pub color_source: BlendFactor, 245 246 /// The operation to apply to the destination color component before applying `color_op`. 247 pub color_destination: BlendFactor, 248 249 /// The operation to apply between the alpha component of the source and destination pixels, 250 /// to produce the final pixel value. 251 pub alpha_op: BlendOp, 252 253 /// The operation to apply to the source alpha component before applying `alpha_op`. 254 pub alpha_source: BlendFactor, 255 256 /// The operation to apply to the destination alpha component before applying `alpha_op`. 257 pub alpha_destination: BlendFactor, 258 } 259 260 impl AttachmentBlend { 261 /// Builds an `AttachmentBlend` where the output of the fragment shader is ignored and the 262 /// destination is untouched. 263 #[inline] ignore_source() -> Self264 pub fn ignore_source() -> Self { 265 Self { 266 color_op: BlendOp::Add, 267 color_source: BlendFactor::Zero, 268 color_destination: BlendFactor::DstColor, 269 alpha_op: BlendOp::Add, 270 alpha_source: BlendFactor::Zero, 271 alpha_destination: BlendFactor::DstColor, 272 } 273 } 274 275 /// Builds an `AttachmentBlend` where the output will be merged with the existing value 276 /// based on the alpha of the source. 277 #[inline] alpha() -> Self278 pub fn alpha() -> Self { 279 Self { 280 color_op: BlendOp::Add, 281 color_source: BlendFactor::SrcAlpha, 282 color_destination: BlendFactor::OneMinusSrcAlpha, 283 alpha_op: BlendOp::Add, 284 alpha_source: BlendFactor::SrcAlpha, 285 alpha_destination: BlendFactor::OneMinusSrcAlpha, 286 } 287 } 288 289 /// Builds an `AttachmentBlend` where the colors are added, and alpha is set to the maximum of 290 /// the two. 291 #[inline] additive() -> Self292 pub fn additive() -> Self { 293 Self { 294 color_op: BlendOp::Add, 295 color_source: BlendFactor::One, 296 color_destination: BlendFactor::One, 297 alpha_op: BlendOp::Max, 298 alpha_source: BlendFactor::One, 299 alpha_destination: BlendFactor::One, 300 } 301 } 302 } 303 304 impl From<AttachmentBlend> for ash::vk::PipelineColorBlendAttachmentState { 305 #[inline] from(val: AttachmentBlend) -> Self306 fn from(val: AttachmentBlend) -> Self { 307 ash::vk::PipelineColorBlendAttachmentState { 308 blend_enable: ash::vk::TRUE, 309 src_color_blend_factor: val.color_source.into(), 310 dst_color_blend_factor: val.color_destination.into(), 311 color_blend_op: val.color_op.into(), 312 src_alpha_blend_factor: val.alpha_source.into(), 313 dst_alpha_blend_factor: val.alpha_destination.into(), 314 alpha_blend_op: val.alpha_op.into(), 315 color_write_mask: ash::vk::ColorComponentFlags::empty(), // Overwritten by GraphicsPipelineBuilder 316 } 317 } 318 } 319 320 vulkan_enum! { 321 #[non_exhaustive] 322 323 /// The operation that takes `source` (output from the fragment shader), `destination` (value 324 /// currently in the framebuffer attachment) and `blend_constant` input values, 325 /// and produces new inputs to be fed to `BlendOp`. 326 /// 327 /// Some operations take `source1` as an input, representing the second source value. The 328 /// [`dual_src_blend`](crate::device::Features::dual_src_blend) feature must be enabled on the 329 /// device when these are used. 330 BlendFactor = BlendFactor(i32); 331 332 /// Always `0`. 333 Zero = ZERO, 334 335 /// Always `1`. 336 One = ONE, 337 338 /// `source` component-wise. 339 SrcColor = SRC_COLOR, 340 341 /// `1 - source` component-wise. 342 OneMinusSrcColor = ONE_MINUS_SRC_COLOR, 343 344 /// `destination` component-wise. 345 DstColor = DST_COLOR, 346 347 /// `1 - destination` component-wise. 348 OneMinusDstColor = ONE_MINUS_DST_COLOR, 349 350 /// `source.a` for all components. 351 SrcAlpha = SRC_ALPHA, 352 353 /// `1 - source.a` for all components. 354 OneMinusSrcAlpha = ONE_MINUS_SRC_ALPHA, 355 356 /// `destination.a` for all components. 357 DstAlpha = DST_ALPHA, 358 359 /// `1 - destination.a` for all components. 360 OneMinusDstAlpha = ONE_MINUS_DST_ALPHA, 361 362 /// `blend_constants` component-wise. 363 ConstantColor = CONSTANT_COLOR, 364 365 /// `1 - blend_constants` component-wise. 366 OneMinusConstantColor = ONE_MINUS_CONSTANT_COLOR, 367 368 /// `blend_constants.a` for all components. 369 /// 370 /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag) 371 /// devices, if this value is used for the `color_source` or `color_destination` blend factors, 372 /// then the 373 /// [`constant_alpha_color_blend_factors`](crate::device::Features::constant_alpha_color_blend_factors) 374 /// feature must be enabled on the device. 375 ConstantAlpha = CONSTANT_ALPHA, 376 377 /// `1 - blend_constants.a` for all components. 378 /// 379 /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag) 380 /// devices, if this value is used for the `color_source` or `color_destination` blend factors, 381 /// then the 382 /// [`constant_alpha_color_blend_factors`](crate::device::Features::constant_alpha_color_blend_factors) 383 /// feature must be enabled on the device. 384 OneMinusConstantAlpha = ONE_MINUS_CONSTANT_ALPHA, 385 386 /// For the alpha component, always `1`. For the color components, 387 /// `min(source.a, 1 - destination.a)` for all components. 388 SrcAlphaSaturate = SRC_ALPHA_SATURATE, 389 390 /// `source1` component-wise. 391 Src1Color = SRC1_COLOR, 392 393 /// `1 - source1` component-wise. 394 OneMinusSrc1Color = ONE_MINUS_SRC1_COLOR, 395 396 /// `source1.a` for all components. 397 Src1Alpha = SRC1_ALPHA, 398 399 /// `1 - source1.a` for all components. 400 OneMinusSrc1Alpha = ONE_MINUS_SRC1_ALPHA, 401 } 402 403 vulkan_enum! { 404 #[non_exhaustive] 405 406 /// The arithmetic operation that is applied between the `source` and `destination` component 407 /// values, after the appropriate `BlendFactor` is applied to both. 408 BlendOp = BlendOp(i32); 409 410 /// `source + destination`. 411 Add = ADD, 412 413 /// `source - destination`. 414 Subtract = SUBTRACT, 415 416 /// `destination - source`. 417 ReverseSubtract = REVERSE_SUBTRACT, 418 419 /// `min(source, destination)`. 420 Min = MIN, 421 422 /// `max(source, destination)`. 423 Max = MAX, 424 425 /* TODO: enable 426 // TODO: document 427 Zero = ZERO_EXT { 428 device_extensions: [ext_blend_operation_advanced], 429 },*/ 430 431 /* TODO: enable 432 // TODO: document 433 Src = SRC_EXT { 434 device_extensions: [ext_blend_operation_advanced], 435 },*/ 436 437 /* TODO: enable 438 // TODO: document 439 Dst = DST_EXT { 440 device_extensions: [ext_blend_operation_advanced], 441 },*/ 442 443 /* TODO: enable 444 // TODO: document 445 SrcOver = SRC_OVER_EXT { 446 device_extensions: [ext_blend_operation_advanced], 447 },*/ 448 449 /* TODO: enable 450 // TODO: document 451 DstOver = DST_OVER_EXT { 452 device_extensions: [ext_blend_operation_advanced], 453 },*/ 454 455 /* TODO: enable 456 // TODO: document 457 SrcIn = SRC_IN_EXT { 458 device_extensions: [ext_blend_operation_advanced], 459 },*/ 460 461 /* TODO: enable 462 // TODO: document 463 DstIn = DST_IN_EXT { 464 device_extensions: [ext_blend_operation_advanced], 465 },*/ 466 467 /* TODO: enable 468 // TODO: document 469 SrcOut = SRC_OUT_EXT { 470 device_extensions: [ext_blend_operation_advanced], 471 },*/ 472 473 /* TODO: enable 474 // TODO: document 475 DstOut = DST_OUT_EXT { 476 device_extensions: [ext_blend_operation_advanced], 477 },*/ 478 479 /* TODO: enable 480 // TODO: document 481 SrcAtop = SRC_ATOP_EXT { 482 device_extensions: [ext_blend_operation_advanced], 483 },*/ 484 485 /* TODO: enable 486 // TODO: document 487 DstAtop = DST_ATOP_EXT { 488 device_extensions: [ext_blend_operation_advanced], 489 },*/ 490 491 /* TODO: enable 492 // TODO: document 493 Xor = XOR_EXT { 494 device_extensions: [ext_blend_operation_advanced], 495 },*/ 496 497 /* TODO: enable 498 // TODO: document 499 Multiply = MULTIPLY_EXT { 500 device_extensions: [ext_blend_operation_advanced], 501 },*/ 502 503 /* TODO: enable 504 // TODO: document 505 Screen = SCREEN_EXT { 506 device_extensions: [ext_blend_operation_advanced], 507 },*/ 508 509 /* TODO: enable 510 // TODO: document 511 Overlay = OVERLAY_EXT { 512 device_extensions: [ext_blend_operation_advanced], 513 },*/ 514 515 /* TODO: enable 516 // TODO: document 517 Darken = DARKEN_EXT { 518 device_extensions: [ext_blend_operation_advanced], 519 },*/ 520 521 /* TODO: enable 522 // TODO: document 523 Lighten = LIGHTEN_EXT { 524 device_extensions: [ext_blend_operation_advanced], 525 },*/ 526 527 /* TODO: enable 528 // TODO: document 529 Colordodge = COLORDODGE_EXT { 530 device_extensions: [ext_blend_operation_advanced], 531 },*/ 532 533 /* TODO: enable 534 // TODO: document 535 Colorburn = COLORBURN_EXT { 536 device_extensions: [ext_blend_operation_advanced], 537 },*/ 538 539 /* TODO: enable 540 // TODO: document 541 Hardlight = HARDLIGHT_EXT { 542 device_extensions: [ext_blend_operation_advanced], 543 },*/ 544 545 /* TODO: enable 546 // TODO: document 547 Softlight = SOFTLIGHT_EXT { 548 device_extensions: [ext_blend_operation_advanced], 549 },*/ 550 551 /* TODO: enable 552 // TODO: document 553 Difference = DIFFERENCE_EXT { 554 device_extensions: [ext_blend_operation_advanced], 555 },*/ 556 557 /* TODO: enable 558 // TODO: document 559 Exclusion = EXCLUSION_EXT { 560 device_extensions: [ext_blend_operation_advanced], 561 },*/ 562 563 /* TODO: enable 564 // TODO: document 565 Invert = INVERT_EXT { 566 device_extensions: [ext_blend_operation_advanced], 567 },*/ 568 569 /* TODO: enable 570 // TODO: document 571 InvertRgb = INVERT_RGB_EXT { 572 device_extensions: [ext_blend_operation_advanced], 573 },*/ 574 575 /* TODO: enable 576 // TODO: document 577 Lineardodge = LINEARDODGE_EXT { 578 device_extensions: [ext_blend_operation_advanced], 579 },*/ 580 581 /* TODO: enable 582 // TODO: document 583 Linearburn = LINEARBURN_EXT { 584 device_extensions: [ext_blend_operation_advanced], 585 },*/ 586 587 /* TODO: enable 588 // TODO: document 589 Vividlight = VIVIDLIGHT_EXT { 590 device_extensions: [ext_blend_operation_advanced], 591 },*/ 592 593 /* TODO: enable 594 // TODO: document 595 Linearlight = LINEARLIGHT_EXT { 596 device_extensions: [ext_blend_operation_advanced], 597 },*/ 598 599 /* TODO: enable 600 // TODO: document 601 Pinlight = PINLIGHT_EXT { 602 device_extensions: [ext_blend_operation_advanced], 603 },*/ 604 605 /* TODO: enable 606 // TODO: document 607 Hardmix = HARDMIX_EXT { 608 device_extensions: [ext_blend_operation_advanced], 609 },*/ 610 611 /* TODO: enable 612 // TODO: document 613 HslHue = HSL_HUE_EXT { 614 device_extensions: [ext_blend_operation_advanced], 615 },*/ 616 617 /* TODO: enable 618 // TODO: document 619 HslSaturation = HSL_SATURATION_EXT { 620 device_extensions: [ext_blend_operation_advanced], 621 },*/ 622 623 /* TODO: enable 624 // TODO: document 625 HslColor = HSL_COLOR_EXT { 626 device_extensions: [ext_blend_operation_advanced], 627 },*/ 628 629 /* TODO: enable 630 // TODO: document 631 HslLuminosity = HSL_LUMINOSITY_EXT { 632 device_extensions: [ext_blend_operation_advanced], 633 },*/ 634 635 /* TODO: enable 636 // TODO: document 637 Plus = PLUS_EXT { 638 device_extensions: [ext_blend_operation_advanced], 639 },*/ 640 641 /* TODO: enable 642 // TODO: document 643 PlusClamped = PLUS_CLAMPED_EXT { 644 device_extensions: [ext_blend_operation_advanced], 645 },*/ 646 647 /* TODO: enable 648 // TODO: document 649 PlusClampedAlpha = PLUS_CLAMPED_ALPHA_EXT { 650 device_extensions: [ext_blend_operation_advanced], 651 },*/ 652 653 /* TODO: enable 654 // TODO: document 655 PlusDarker = PLUS_DARKER_EXT { 656 device_extensions: [ext_blend_operation_advanced], 657 },*/ 658 659 /* TODO: enable 660 // TODO: document 661 Minus = MINUS_EXT { 662 device_extensions: [ext_blend_operation_advanced], 663 },*/ 664 665 /* TODO: enable 666 // TODO: document 667 MinusClamped = MINUS_CLAMPED_EXT { 668 device_extensions: [ext_blend_operation_advanced], 669 },*/ 670 671 /* TODO: enable 672 // TODO: document 673 Contrast = CONTRAST_EXT { 674 device_extensions: [ext_blend_operation_advanced], 675 },*/ 676 677 /* TODO: enable 678 // TODO: document 679 InvertOvg = INVERT_OVG_EXT { 680 device_extensions: [ext_blend_operation_advanced], 681 },*/ 682 683 /* TODO: enable 684 // TODO: document 685 Red = RED_EXT { 686 device_extensions: [ext_blend_operation_advanced], 687 },*/ 688 689 /* TODO: enable 690 // TODO: document 691 Green = GREEN_EXT { 692 device_extensions: [ext_blend_operation_advanced], 693 },*/ 694 695 /* TODO: enable 696 // TODO: document 697 Blue = BLUE_EXT { 698 device_extensions: [ext_blend_operation_advanced], 699 },*/ 700 } 701 702 vulkan_bitflags! { 703 /// A mask specifying color components that can be written to a framebuffer attachment. 704 ColorComponents = ColorComponentFlags(u32); 705 706 /// The red component. 707 R = R, 708 709 /// The green component. 710 G = G, 711 712 /// The blue component. 713 B = B, 714 715 /// The alpha component. 716 A = A, 717 } 718