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 //! Defines 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, 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 25 /// Describes how the color output of the fragment shader is written to the attachment. See the 26 /// documentation of the `blend` module for more info. 27 #[derive(Debug, Clone, PartialEq)] 28 pub struct Blend { 29 pub logic_op: Option<LogicOp>, 30 31 pub attachments: AttachmentsBlend, 32 33 /// The constant color to use for the `Constant*` blending operation. 34 /// 35 /// If you pass `None`, then this state will be considered as dynamic and the blend constants 36 /// will need to be set when you build the command buffer. 37 pub blend_constants: Option<[f32; 4]>, 38 } 39 40 impl Blend { 41 /// Returns a `Blend` object that directly writes colors and alpha on the surface. 42 #[inline] pass_through() -> Blend43 pub fn pass_through() -> Blend { 44 Blend { 45 logic_op: None, 46 attachments: AttachmentsBlend::Collective(AttachmentBlend::pass_through()), 47 blend_constants: Some([0.0, 0.0, 0.0, 0.0]), 48 } 49 } 50 51 /// Returns a `Blend` object that adds transparent objects over others. 52 #[inline] alpha_blending() -> Blend53 pub fn alpha_blending() -> Blend { 54 Blend { 55 logic_op: None, 56 attachments: AttachmentsBlend::Collective(AttachmentBlend::alpha_blending()), 57 blend_constants: Some([0.0, 0.0, 0.0, 0.0]), 58 } 59 } 60 } 61 62 /// Describes how the blending system should behave. 63 #[derive(Debug, Clone, PartialEq, Eq)] 64 pub enum AttachmentsBlend { 65 /// All the framebuffer attachments will use the same blending. 66 Collective(AttachmentBlend), 67 68 /// Each attachment will behave differently. Note that this requires enabling the 69 /// `independent_blend` feature. 70 Individual(Vec<AttachmentBlend>), 71 } 72 73 /// Describes how the blending system should behave for an individual attachment. 74 #[derive(Debug, Clone, PartialEq, Eq)] 75 pub struct AttachmentBlend { 76 // TODO: could be automatically determined from the other params 77 /// If false, blending is ignored and the output is directly written to the attachment. 78 pub enabled: bool, 79 80 pub color_op: BlendOp, 81 pub color_source: BlendFactor, 82 pub color_destination: BlendFactor, 83 84 pub alpha_op: BlendOp, 85 pub alpha_source: BlendFactor, 86 pub alpha_destination: BlendFactor, 87 88 pub mask_red: bool, 89 pub mask_green: bool, 90 pub mask_blue: bool, 91 pub mask_alpha: bool, 92 } 93 94 impl AttachmentBlend { 95 /// Builds an `AttachmentBlend` where blending is disabled. 96 #[inline] pass_through() -> AttachmentBlend97 pub fn pass_through() -> AttachmentBlend { 98 AttachmentBlend { 99 enabled: false, 100 color_op: BlendOp::Add, 101 color_source: BlendFactor::Zero, 102 color_destination: BlendFactor::One, 103 alpha_op: BlendOp::Add, 104 alpha_source: BlendFactor::Zero, 105 alpha_destination: BlendFactor::One, 106 mask_red: true, 107 mask_green: true, 108 mask_blue: true, 109 mask_alpha: true, 110 } 111 } 112 113 /// Builds an `AttachmentBlend` where the output of the fragment shader is ignored and the 114 /// destination is untouched. 115 #[inline] ignore_source() -> AttachmentBlend116 pub fn ignore_source() -> AttachmentBlend { 117 AttachmentBlend { 118 enabled: true, 119 color_op: BlendOp::Add, 120 color_source: BlendFactor::Zero, 121 color_destination: BlendFactor::DstColor, 122 alpha_op: BlendOp::Add, 123 alpha_source: BlendFactor::Zero, 124 alpha_destination: BlendFactor::DstColor, 125 mask_red: true, 126 mask_green: true, 127 mask_blue: true, 128 mask_alpha: true, 129 } 130 } 131 132 /// Builds an `AttachmentBlend` where the output will be merged with the existing value 133 /// based on the alpha of the source. 134 #[inline] alpha_blending() -> AttachmentBlend135 pub fn alpha_blending() -> AttachmentBlend { 136 AttachmentBlend { 137 enabled: true, 138 color_op: BlendOp::Add, 139 color_source: BlendFactor::SrcAlpha, 140 color_destination: BlendFactor::OneMinusSrcAlpha, 141 alpha_op: BlendOp::Add, 142 alpha_source: BlendFactor::SrcAlpha, 143 alpha_destination: BlendFactor::OneMinusSrcAlpha, 144 mask_red: true, 145 mask_green: true, 146 mask_blue: true, 147 mask_alpha: true, 148 } 149 } 150 } 151 152 impl From<AttachmentBlend> for ash::vk::PipelineColorBlendAttachmentState { 153 #[inline] from(val: AttachmentBlend) -> Self154 fn from(val: AttachmentBlend) -> Self { 155 ash::vk::PipelineColorBlendAttachmentState { 156 blend_enable: if val.enabled { 157 ash::vk::TRUE 158 } else { 159 ash::vk::FALSE 160 }, 161 src_color_blend_factor: val.color_source.into(), 162 dst_color_blend_factor: val.color_destination.into(), 163 color_blend_op: val.color_op.into(), 164 src_alpha_blend_factor: val.alpha_source.into(), 165 dst_alpha_blend_factor: val.alpha_destination.into(), 166 alpha_blend_op: val.alpha_op.into(), 167 color_write_mask: { 168 let mut mask = ash::vk::ColorComponentFlags::empty(); 169 if val.mask_red { 170 mask |= ash::vk::ColorComponentFlags::R; 171 } 172 if val.mask_green { 173 mask |= ash::vk::ColorComponentFlags::G; 174 } 175 if val.mask_blue { 176 mask |= ash::vk::ColorComponentFlags::B; 177 } 178 if val.mask_alpha { 179 mask |= ash::vk::ColorComponentFlags::A; 180 } 181 mask 182 }, 183 } 184 } 185 } 186 187 /// Which logical operation to apply to the output values. 188 /// 189 /// The operation is applied individually for each channel (red, green, blue and alpha). 190 /// 191 /// Only relevant for integer or unsigned attachments. 192 /// 193 /// Also note that some implementations don't support logic operations. 194 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 195 #[repr(i32)] 196 pub enum LogicOp { 197 /// Returns `0`. 198 Clear = ash::vk::LogicOp::CLEAR.as_raw(), 199 /// Returns `source & destination`. 200 And = ash::vk::LogicOp::AND.as_raw(), 201 /// Returns `source & !destination`. 202 AndReverse = ash::vk::LogicOp::AND_REVERSE.as_raw(), 203 /// Returns `source`. 204 Copy = ash::vk::LogicOp::COPY.as_raw(), 205 /// Returns `!source & destination`. 206 AndInverted = ash::vk::LogicOp::AND_INVERTED.as_raw(), 207 /// Returns `destination`. 208 Noop = ash::vk::LogicOp::NO_OP.as_raw(), 209 /// Returns `source ^ destination`. 210 Xor = ash::vk::LogicOp::XOR.as_raw(), 211 /// Returns `source | destination`. 212 Or = ash::vk::LogicOp::OR.as_raw(), 213 /// Returns `!(source | destination)`. 214 Nor = ash::vk::LogicOp::NOR.as_raw(), 215 /// Returns `!(source ^ destination)`. 216 Equivalent = ash::vk::LogicOp::EQUIVALENT.as_raw(), 217 /// Returns `!destination`. 218 Invert = ash::vk::LogicOp::INVERT.as_raw(), 219 /// Returns `source | !destination. 220 OrReverse = ash::vk::LogicOp::OR_REVERSE.as_raw(), 221 /// Returns `!source`. 222 CopyInverted = ash::vk::LogicOp::COPY_INVERTED.as_raw(), 223 /// Returns `!source | destination`. 224 OrInverted = ash::vk::LogicOp::OR_INVERTED.as_raw(), 225 /// Returns `!(source & destination)`. 226 Nand = ash::vk::LogicOp::NAND.as_raw(), 227 /// Returns `!0` (all bits set to 1). 228 Set = ash::vk::LogicOp::SET.as_raw(), 229 } 230 231 impl From<LogicOp> for ash::vk::LogicOp { 232 #[inline] from(val: LogicOp) -> Self233 fn from(val: LogicOp) -> Self { 234 Self::from_raw(val as i32) 235 } 236 } 237 238 impl Default for LogicOp { 239 #[inline] default() -> LogicOp240 fn default() -> LogicOp { 241 LogicOp::Noop 242 } 243 } 244 245 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 246 #[repr(i32)] 247 pub enum BlendOp { 248 Add = ash::vk::BlendOp::ADD.as_raw(), 249 Subtract = ash::vk::BlendOp::SUBTRACT.as_raw(), 250 ReverseSubtract = ash::vk::BlendOp::REVERSE_SUBTRACT.as_raw(), 251 Min = ash::vk::BlendOp::MIN.as_raw(), 252 Max = ash::vk::BlendOp::MAX.as_raw(), 253 } 254 255 impl From<BlendOp> for ash::vk::BlendOp { 256 #[inline] from(val: BlendOp) -> Self257 fn from(val: BlendOp) -> Self { 258 Self::from_raw(val as i32) 259 } 260 } 261 262 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 263 #[repr(i32)] 264 pub enum BlendFactor { 265 Zero = ash::vk::BlendFactor::ZERO.as_raw(), 266 One = ash::vk::BlendFactor::ONE.as_raw(), 267 SrcColor = ash::vk::BlendFactor::SRC_COLOR.as_raw(), 268 OneMinusSrcColor = ash::vk::BlendFactor::ONE_MINUS_SRC_COLOR.as_raw(), 269 DstColor = ash::vk::BlendFactor::DST_COLOR.as_raw(), 270 OneMinusDstColor = ash::vk::BlendFactor::ONE_MINUS_DST_COLOR.as_raw(), 271 SrcAlpha = ash::vk::BlendFactor::SRC_ALPHA.as_raw(), 272 OneMinusSrcAlpha = ash::vk::BlendFactor::ONE_MINUS_SRC_ALPHA.as_raw(), 273 DstAlpha = ash::vk::BlendFactor::DST_ALPHA.as_raw(), 274 OneMinusDstAlpha = ash::vk::BlendFactor::ONE_MINUS_DST_ALPHA.as_raw(), 275 ConstantColor = ash::vk::BlendFactor::CONSTANT_COLOR.as_raw(), 276 OneMinusConstantColor = ash::vk::BlendFactor::ONE_MINUS_CONSTANT_COLOR.as_raw(), 277 ConstantAlpha = ash::vk::BlendFactor::CONSTANT_ALPHA.as_raw(), 278 OneMinusConstantAlpha = ash::vk::BlendFactor::ONE_MINUS_CONSTANT_ALPHA.as_raw(), 279 SrcAlphaSaturate = ash::vk::BlendFactor::SRC_ALPHA_SATURATE.as_raw(), 280 Src1Color = ash::vk::BlendFactor::SRC1_COLOR.as_raw(), 281 OneMinusSrc1Color = ash::vk::BlendFactor::ONE_MINUS_SRC1_COLOR.as_raw(), 282 Src1Alpha = ash::vk::BlendFactor::SRC1_ALPHA.as_raw(), 283 OneMinusSrc1Alpha = ash::vk::BlendFactor::ONE_MINUS_SRC1_ALPHA.as_raw(), 284 } 285 286 impl From<BlendFactor> for ash::vk::BlendFactor { 287 #[inline] from(val: BlendFactor) -> Self288 fn from(val: BlendFactor) -> Self { 289 Self::from_raw(val as i32) 290 } 291 } 292