aboutsummaryrefslogtreecommitdiff
path: root/src/pipeline/blend.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/pipeline/blend.rs')
-rw-r--r--src/pipeline/blend.rs291
1 files changed, 291 insertions, 0 deletions
diff --git a/src/pipeline/blend.rs b/src/pipeline/blend.rs
new file mode 100644
index 0000000..7863b8a
--- /dev/null
+++ b/src/pipeline/blend.rs
@@ -0,0 +1,291 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// 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<LogicOp>,
+
+ 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<AttachmentBlend>),
+}
+
+/// 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<AttachmentBlend> 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<LogicOp> 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<BlendOp> 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<BlendFactor> for ash::vk::BlendFactor {
+ #[inline]
+ fn from(val: BlendFactor) -> Self {
+ Self::from_raw(val as i32)
+ }
+}