// Copyright (c) 2016 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. //! Defines how the color output of the fragment shader is written to the attachment. //! //! # Blending in details //! //! There are three kinds of color attachments for the purpose of blending: //! //! - Attachments with a floating-point, fixed point format. //! - Attachments with a (non-normalized) integer format. //! - Attachments with a normalized integer format. //! //! For floating-point and fixed-point formats, the blending operation is applied. For integer //! formats, the logic operation is applied. For normalized integer formats, the logic operation //! will take precedence if it is activated, otherwise the blending operation is applied. //! /// Describes how the color output of the fragment shader is written to the attachment. See the /// documentation of the `blend` module for more info. #[derive(Debug, Clone, PartialEq)] pub struct Blend { pub logic_op: Option, pub attachments: AttachmentsBlend, /// The constant color to use for the `Constant*` blending operation. /// /// If you pass `None`, then this state will be considered as dynamic and the blend constants /// will need to be set when you build the command buffer. pub blend_constants: Option<[f32; 4]>, } impl Blend { /// Returns a `Blend` object that directly writes colors and alpha on the surface. #[inline] pub fn pass_through() -> Blend { Blend { logic_op: None, attachments: AttachmentsBlend::Collective(AttachmentBlend::pass_through()), blend_constants: Some([0.0, 0.0, 0.0, 0.0]), } } /// Returns a `Blend` object that adds transparent objects over others. #[inline] pub fn alpha_blending() -> Blend { Blend { logic_op: None, attachments: AttachmentsBlend::Collective(AttachmentBlend::alpha_blending()), blend_constants: Some([0.0, 0.0, 0.0, 0.0]), } } } /// Describes how the blending system should behave. #[derive(Debug, Clone, PartialEq, Eq)] pub enum AttachmentsBlend { /// All the framebuffer attachments will use the same blending. Collective(AttachmentBlend), /// Each attachment will behave differently. Note that this requires enabling the /// `independent_blend` feature. Individual(Vec), } /// Describes how the blending system should behave for an individual attachment. #[derive(Debug, Clone, PartialEq, Eq)] pub struct AttachmentBlend { // TODO: could be automatically determined from the other params /// If false, blending is ignored and the output is directly written to the attachment. pub enabled: bool, pub color_op: BlendOp, pub color_source: BlendFactor, pub color_destination: BlendFactor, pub alpha_op: BlendOp, pub alpha_source: BlendFactor, pub alpha_destination: BlendFactor, pub mask_red: bool, pub mask_green: bool, pub mask_blue: bool, pub mask_alpha: bool, } impl AttachmentBlend { /// Builds an `AttachmentBlend` where blending is disabled. #[inline] pub fn pass_through() -> AttachmentBlend { AttachmentBlend { enabled: false, color_op: BlendOp::Add, color_source: BlendFactor::Zero, color_destination: BlendFactor::One, alpha_op: BlendOp::Add, alpha_source: BlendFactor::Zero, alpha_destination: BlendFactor::One, mask_red: true, mask_green: true, mask_blue: true, mask_alpha: true, } } /// Builds an `AttachmentBlend` where the output of the fragment shader is ignored and the /// destination is untouched. #[inline] pub fn ignore_source() -> AttachmentBlend { AttachmentBlend { enabled: true, color_op: BlendOp::Add, color_source: BlendFactor::Zero, color_destination: BlendFactor::DstColor, alpha_op: BlendOp::Add, alpha_source: BlendFactor::Zero, alpha_destination: BlendFactor::DstColor, mask_red: true, mask_green: true, mask_blue: true, mask_alpha: true, } } /// Builds an `AttachmentBlend` where the output will be merged with the existing value /// based on the alpha of the source. #[inline] pub fn alpha_blending() -> AttachmentBlend { AttachmentBlend { enabled: true, color_op: BlendOp::Add, color_source: BlendFactor::SrcAlpha, color_destination: BlendFactor::OneMinusSrcAlpha, alpha_op: BlendOp::Add, alpha_source: BlendFactor::SrcAlpha, alpha_destination: BlendFactor::OneMinusSrcAlpha, mask_red: true, mask_green: true, mask_blue: true, mask_alpha: true, } } } impl From for ash::vk::PipelineColorBlendAttachmentState { #[inline] fn from(val: AttachmentBlend) -> Self { ash::vk::PipelineColorBlendAttachmentState { blend_enable: if val.enabled { ash::vk::TRUE } else { ash::vk::FALSE }, src_color_blend_factor: val.color_source.into(), dst_color_blend_factor: val.color_destination.into(), color_blend_op: val.color_op.into(), src_alpha_blend_factor: val.alpha_source.into(), dst_alpha_blend_factor: val.alpha_destination.into(), alpha_blend_op: val.alpha_op.into(), color_write_mask: { let mut mask = ash::vk::ColorComponentFlags::empty(); if val.mask_red { mask |= ash::vk::ColorComponentFlags::R; } if val.mask_green { mask |= ash::vk::ColorComponentFlags::G; } if val.mask_blue { mask |= ash::vk::ColorComponentFlags::B; } if val.mask_alpha { mask |= ash::vk::ColorComponentFlags::A; } mask }, } } } /// Which logical operation to apply to the output values. /// /// The operation is applied individually for each channel (red, green, blue and alpha). /// /// Only relevant for integer or unsigned attachments. /// /// Also note that some implementations don't support logic operations. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(i32)] pub enum LogicOp { /// Returns `0`. Clear = ash::vk::LogicOp::CLEAR.as_raw(), /// Returns `source & destination`. And = ash::vk::LogicOp::AND.as_raw(), /// Returns `source & !destination`. AndReverse = ash::vk::LogicOp::AND_REVERSE.as_raw(), /// Returns `source`. Copy = ash::vk::LogicOp::COPY.as_raw(), /// Returns `!source & destination`. AndInverted = ash::vk::LogicOp::AND_INVERTED.as_raw(), /// Returns `destination`. Noop = ash::vk::LogicOp::NO_OP.as_raw(), /// Returns `source ^ destination`. Xor = ash::vk::LogicOp::XOR.as_raw(), /// Returns `source | destination`. Or = ash::vk::LogicOp::OR.as_raw(), /// Returns `!(source | destination)`. Nor = ash::vk::LogicOp::NOR.as_raw(), /// Returns `!(source ^ destination)`. Equivalent = ash::vk::LogicOp::EQUIVALENT.as_raw(), /// Returns `!destination`. Invert = ash::vk::LogicOp::INVERT.as_raw(), /// Returns `source | !destination. OrReverse = ash::vk::LogicOp::OR_REVERSE.as_raw(), /// Returns `!source`. CopyInverted = ash::vk::LogicOp::COPY_INVERTED.as_raw(), /// Returns `!source | destination`. OrInverted = ash::vk::LogicOp::OR_INVERTED.as_raw(), /// Returns `!(source & destination)`. Nand = ash::vk::LogicOp::NAND.as_raw(), /// Returns `!0` (all bits set to 1). Set = ash::vk::LogicOp::SET.as_raw(), } impl From for ash::vk::LogicOp { #[inline] fn from(val: LogicOp) -> Self { Self::from_raw(val as i32) } } impl Default for LogicOp { #[inline] fn default() -> LogicOp { LogicOp::Noop } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(i32)] pub enum BlendOp { Add = ash::vk::BlendOp::ADD.as_raw(), Subtract = ash::vk::BlendOp::SUBTRACT.as_raw(), ReverseSubtract = ash::vk::BlendOp::REVERSE_SUBTRACT.as_raw(), Min = ash::vk::BlendOp::MIN.as_raw(), Max = ash::vk::BlendOp::MAX.as_raw(), } impl From for ash::vk::BlendOp { #[inline] fn from(val: BlendOp) -> Self { Self::from_raw(val as i32) } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(i32)] pub enum BlendFactor { Zero = ash::vk::BlendFactor::ZERO.as_raw(), One = ash::vk::BlendFactor::ONE.as_raw(), SrcColor = ash::vk::BlendFactor::SRC_COLOR.as_raw(), OneMinusSrcColor = ash::vk::BlendFactor::ONE_MINUS_SRC_COLOR.as_raw(), DstColor = ash::vk::BlendFactor::DST_COLOR.as_raw(), OneMinusDstColor = ash::vk::BlendFactor::ONE_MINUS_DST_COLOR.as_raw(), SrcAlpha = ash::vk::BlendFactor::SRC_ALPHA.as_raw(), OneMinusSrcAlpha = ash::vk::BlendFactor::ONE_MINUS_SRC_ALPHA.as_raw(), DstAlpha = ash::vk::BlendFactor::DST_ALPHA.as_raw(), OneMinusDstAlpha = ash::vk::BlendFactor::ONE_MINUS_DST_ALPHA.as_raw(), ConstantColor = ash::vk::BlendFactor::CONSTANT_COLOR.as_raw(), OneMinusConstantColor = ash::vk::BlendFactor::ONE_MINUS_CONSTANT_COLOR.as_raw(), ConstantAlpha = ash::vk::BlendFactor::CONSTANT_ALPHA.as_raw(), OneMinusConstantAlpha = ash::vk::BlendFactor::ONE_MINUS_CONSTANT_ALPHA.as_raw(), SrcAlphaSaturate = ash::vk::BlendFactor::SRC_ALPHA_SATURATE.as_raw(), Src1Color = ash::vk::BlendFactor::SRC1_COLOR.as_raw(), OneMinusSrc1Color = ash::vk::BlendFactor::ONE_MINUS_SRC1_COLOR.as_raw(), Src1Alpha = ash::vk::BlendFactor::SRC1_ALPHA.as_raw(), OneMinusSrc1Alpha = ash::vk::BlendFactor::ONE_MINUS_SRC1_ALPHA.as_raw(), } impl From for ash::vk::BlendFactor { #[inline] fn from(val: BlendFactor) -> Self { Self::from_raw(val as i32) } }