diff options
Diffstat (limited to 'src/pipeline/blend.rs')
-rw-r--r-- | src/pipeline/blend.rs | 291 |
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) + } +} |