blob: 7863b8a0f12c05b287d585d54203f82520034641 [file] [log] [blame]
// 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)
}
}