26.1. Blending

Blending combines the incoming “source” fragment’s R, G, B, and A values with the “destination” R, G, B, and A values of each sample stored in the framebuffer at the fragment’s $(x_f,y_f)$ location. Blending is performed for each pixel sample, rather than just once for each fragment.

Source and destination values are combined according to the blend operation, quadruplets of source and destination weighting factors determined by the blend factors, and a blend constant, to obtain a new set of R, G, B, and A values, as described below.

Blending is computed and applied separately to each color attachment used by the subpass, with separate controls for each attachment.

Prior to performing the blend operation, signed and unsigned normalized fixed-point color components undergo an implied conversion to floating-point as specified by Conversion from Normalized Fixed-Point to Floating-Point. Blending computations are treated as if carried out in floating-point, and will be performed with a precision and dynamic range no lower than that used to represent destination components.

Blending applies only to fixed-point and floating-point color attachments. If the color attachment has an integer format, blending is not applied.

The pipeline blend state is included in the VkPipelineColorBlendStateCreateInfo structure during graphics pipeline creation:

The VkPipelineColorBlendStateCreateInfo structure is defined as:

 

typedef struct VkPipelineColorBlendStateCreateInfo {
    VkStructureType                               sType;
    const void*                                   pNext;
    VkPipelineColorBlendStateCreateFlags          flags;
    VkBool32                                      logicOpEnable;
    VkLogicOp                                     logicOp;
    uint32_t                                      attachmentCount;
    const VkPipelineColorBlendAttachmentState*    pAttachments;
    float                                         blendConstants[4];
} VkPipelineColorBlendStateCreateInfo;

Each element of the pAttachments array is a VkPipelineColorBlendAttachmentState structure specifying per-target blending state for each individual color attachment. If the independent blending feature is not enabled on the device, all VkPipelineColorBlendAttachmentState elements in the pAttachments array must be identical.

The VkPipelineColorBlendAttachmentState structure is defined as:

 

typedef struct VkPipelineColorBlendAttachmentState {
    VkBool32                 blendEnable;
    VkBlendFactor            srcColorBlendFactor;
    VkBlendFactor            dstColorBlendFactor;
    VkBlendOp                colorBlendOp;
    VkBlendFactor            srcAlphaBlendFactor;
    VkBlendFactor            dstAlphaBlendFactor;
    VkBlendOp                alphaBlendOp;
    VkColorComponentFlags    colorWriteMask;
} VkPipelineColorBlendAttachmentState;

26.1.1. Blend Factors

The source and destination color and alpha blending factors are selected from the enum:

 

typedef enum VkBlendFactor {
    VK_BLEND_FACTOR_ZERO = 0,
    VK_BLEND_FACTOR_ONE = 1,
    VK_BLEND_FACTOR_SRC_COLOR = 2,
    VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3,
    VK_BLEND_FACTOR_DST_COLOR = 4,
    VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5,
    VK_BLEND_FACTOR_SRC_ALPHA = 6,
    VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7,
    VK_BLEND_FACTOR_DST_ALPHA = 8,
    VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9,
    VK_BLEND_FACTOR_CONSTANT_COLOR = 10,
    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11,
    VK_BLEND_FACTOR_CONSTANT_ALPHA = 12,
    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13,
    VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14,
    VK_BLEND_FACTOR_SRC1_COLOR = 15,
    VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16,
    VK_BLEND_FACTOR_SRC1_ALPHA = 17,
    VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18,
} VkBlendFactor;

The semantics of each enum value is described in the table below:

Table 26.1. Blend Factors

VkBlendFactor RGB Blend Factors ( $S_r,S_g,S_b$ ) or ( $D_r,D_g,D_b$ ) Alpha Blend Factor ( $S_a$ or $D_a$ )

VK_BLEND_FACTOR_ZERO

$(0,0,0)$

$0$

VK_BLEND_FACTOR_ONE

$(1,1,1)$

$1$

VK_BLEND_FACTOR_SRC_COLOR

$(R_{s0},G_{s0},B_{s0})$

$A_{s0}$

VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR

$(1-R_{s0},1-G_{s0},1-B_{s0})$

$1-A_{s0}$

VK_BLEND_FACTOR_DST_COLOR

$(R_d,G_d,B_d)$

$A_d$

VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR

$(1-R_d,1-G_d,1-B_d)$

$1-A_d$

VK_BLEND_FACTOR_SRC_ALPHA

$(A_{s0},A_{s0},A_{s0})$

$A_{s0}$

VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA

$(1-A_{s0},1-A_{s0},1-A_{s0})$

$1-A_{s0}$

VK_BLEND_FACTOR_DST_ALPHA

$(A_d,A_d,A_d)$

$A_d$

VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA

$(1-A_d,1-A_d,1-A_d)$

$1-A_d$

VK_BLEND_FACTOR_CONSTANT_COLOR

$(R_c,G_c,B_c)$

$A_c$

VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR

$(1-R_c,1-G_c,1-B_c)$

$1-A_c$

VK_BLEND_FACTOR_CONSTANT_ALPHA

$(A_c,A_c,A_c)$

$A_c$

VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA

$(1-A_c,1-A_c,1-A_c)$

$1-A_c$

VK_BLEND_FACTOR_SRC_ALPHA_SATURATE

$(f,f,f); f=\min(A_{s0},1-A_d)$

$1$

VK_BLEND_FACTOR_SRC1_COLOR

$(R_{s1},G_{s1},B_{s1})$

$A_{s1}$

VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR

$(1-R_{s1},1-G_{s1},1-B_{s1})$

$1-A_{s1}$

VK_BLEND_FACTOR_SRC1_ALPHA

$(A_{s1},A_{s1},A_{s1})$

$A_{s1}$

VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA

$(1-A_{s1},1-A_{s1},1-A_{s1})$

$1-A_{s1}$


In this table, the following conventions are used:

  • $R_{s0},G_{s0},B_{s0}$ and $A_{s0}$ represent the first source color R, G, B, and A components, respectively, for the fragment output location corresponding to the color attachment being blended.
  • $R_{s1},G_{s1},B_{s1}$ and $A_{s1}$ represent the second source color R, G, B, and A components, respectively, used in dual source blending modes, for the fragment output location corresponding to the color attachment being blended.
  • $R_d,G_d,B_d$ and $A_d$ represent the R, G, B, and A components of the destination color. That is, the color currently in the corresponding color attachment for this fragment/sample.
  • $R_c,G_c,B_c$ and $A_c$ represent the blend constant R, G, B, and A components, respectively.

If the pipeline state object is created without the VK_DYNAMIC_STATE_BLEND_CONSTANTS dynamic state enabled then the “blend constant” $(R_c,G_c,B_c,A_c)$ is specified via the blendConstants member of VkPipelineColorBlendStateCreateInfo. Otherwise the blend constant is dynamically set and changed by calling the command:

 

void vkCmdSetBlendConstants(
    VkCommandBuffer                             commandBuffer,
    const float                                 blendConstants[4]);

  • commandBuffer is the command buffer into which the command will be recorded.
  • blendConstants is an array of four values specifying the R, G, B, and A components of the blend constant color used in blending, depending on the blend factor.

26.1.2. Dual-Source Blending

Blend factors that use the secondary color input $(R_{s1},G_{s1},B_{s1},A_{s1})$ (VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, VK_BLEND_FACTOR_SRC1_ALPHA, and VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA) may consume hardware resources that could otherwise be used for rendering to multiple color attachments. Therefore, the number of color attachments that can be used in a framebuffer may be lower when using dual-source blending.

Dual-source blending is only supported if the dualSrcBlend feature is enabled.

The maximum number of color attachments that can be used in a subpass when using dual-source blending functions is implementation-dependent and is reported as the maxFragmentDualSrcAttachments member of VkPhysicalDeviceLimits.

When using a fragment shader with dual-source blending functions, the color outputs are bound to the first and second inputs of the blender using the Index decoration, as described in Fragment Output Interface. If the second color input to the blender is not written in the shader, or if no output is bound to the second input of a blender, the result of the blending operation is not defined.

26.1.3. Blend Operations

Once the source and destination blend factors have been selected, they along with the source and destination components are passed to the blending operation. The blending operations are selected from the following enum, with RGB and alpha components potentially using different blend operations:

 

typedef enum VkBlendOp {
    VK_BLEND_OP_ADD = 0,
    VK_BLEND_OP_SUBTRACT = 1,
    VK_BLEND_OP_REVERSE_SUBTRACT = 2,
    VK_BLEND_OP_MIN = 3,
    VK_BLEND_OP_MAX = 4,
} VkBlendOp;

The semantics of each enum value is described in the table below:

Table 26.2. Blend Operations

VkBlendOp RGB Components Alpha Component

VK_BLEND_OP_ADD

$R=R_{s0}\times S_r+R_d\times D_r$ $G=G_{s0}\times S_g+G_d\times D_g$ $B=B_{s0}\times S_b+B_d\times D_b$

$A=A_{s0}\times S_a+A_d\times D_a$

VK_BLEND_OP_SUBTRACT

$R=R_{s0}\times S_r-R_d\times D_r$ $G=G_{s0}\times S_g-G_d\times D_g$ $B=B_{s0}\times S_b-B_d\times D_b$

$A=A_{s0}\times S_a-A_d\times D_a$

VK_BLEND_OP_REVERSE_SUBTRACT

$R=R_d\times D_r-R_{s0}\times S_r$ $G=G_d\times D_g-G_{s0}\times S_g$ $B=B_d\times D_b-B_{s0}\times S_b$

$A=A_d\times D_a-A_{s0}\times S_a$

VK_BLEND_OP_MIN

$R=\min(R_{s0},R_d)$ $G=\min(G_{s0},G_d)$ $B=\min(B_{s0},B_d)$

$A=\min(A_{s0},A_d)$

VK_BLEND_OP_MAX

$R=\max(R_{s0},R_d)$ $G=\max(G_{s0},G_d)$ $B=\max(B_{s0},B_d)$

$A=\max(A_{s0},A_d)$


In this table, the following conventions are used:

  • $R_{s0},G_{s0},B_{s0}$ and $A_{s0}$ represent the first source color R, G, B, and A components, respectively.
  • $R_d,G_d,B_d$ and $A_d$ represent the R, G, B, and A components of the destination color. That is, the color currently in the corresponding color attachment for this fragment/sample.
  • $S_r,S_g,S_b$ and $S_a$ represent the source blend factor R, G, B, and A components, respectively.
  • $D_r,D_g,D_b$ and $D_a$ represent the destination blend factor R, G, B, and A components, respectively.

The blending operation produces a new set of values $R, G, B$ and $A$ , which are written to the framebuffer attachment. If blending is not enabled for this attachment, then $R, G, B$ and $A$ are assigned $R_{s0},G_{s0},B_{s0}$ and $A_{s0}$ , respectively.

If the color attachment is fixed-point, the components of the source and destination values and blend factors are each clamped to $[0,1]$ or $[-1,1]$ respectively for an unsigned normalized or signed normalized color attachment prior to evaluating the blend operations. If the color attachment is floating-point, no clamping occurs.

The colorWriteMask member of VkPipelineColorBlendAttachmentState determines whether the final color values $R, G, B$ and $A$ are written to the framebuffer attachment. colorWriteMask is any combination of the following bits:

 

typedef enum VkColorComponentFlagBits {
    VK_COLOR_COMPONENT_R_BIT = 0x00000001,
    VK_COLOR_COMPONENT_G_BIT = 0x00000002,
    VK_COLOR_COMPONENT_B_BIT = 0x00000004,
    VK_COLOR_COMPONENT_A_BIT = 0x00000008,
} VkColorComponentFlagBits;

If VK_COLOR_COMPONENT_R_BIT is set, then the $R$ value is written to color attachment for the appropriate sample, otherwise the value in memory is unmodified. The VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_B_BIT, and VK_COLOR_COMPONENT_A_BIT bits similarly control writing of the $G, B,$ and $A$ values. The colorWriteMask is applied regardless of whether blending is enabled.

If the numeric format of a framebuffer attachment uses sRGB encoding, the R, G, and B destination color values (after conversion from fixed-point to floating-point) are considered to be encoded for the sRGB color space and hence are linearized prior to their use in blending. Each R, G, and B component is converted from nonlinear to linear as described in the “KHR_DF_TRANSFER_SRGB” section of the Khronos Data Format Specification. If the format is not sRGB, no linearization is performed.

If the numeric format of a framebuffer attachment uses sRGB encoding, then the final R, G and B values are converted into the nonlinear sRGB representation before being written to the framebuffer attachment as described in the “KHR_DF_TRANSFER_SRGB” section of the Khronos Data Format Specification.

If the framebuffer color attachment numeric format is not sRGB encoded then the resulting $c_s$ values for R, G and B are unmodified. The value of A is never sRGB encoded. That is, the alpha component is always stored in memory as linear.

If the framebuffer color attachment is VK_ATTACHMENT_UNUSED, no writes are performed through that attachment. Framebuffer color attachments greater than or equal to VkSubpassDescription::colorAttachmentCount perform no writes.