• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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