Aqoole_Hateenaの技術日記

vulkan+raytraceで色々描いてます

Blending Stageの指定

Blending Stage

Blending Stageではcolor blendの指定を行う。
aqoole-hateena.hatenablog.com

color blendとは

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 (xf,yf) location. Blending is performed for each color sample covered by the fragment, rather than just once for each fragment.
Vulkan® 1.2.203 - A Specification (with all registered Vulkan extensions)

color blendとは、source colorとdst colorのfragments(RGBA)を混ぜ合わせて、対応するframe bufferの位置(x_f, y_f)に格納することである。
つまりsource color, dst colorの選び方と、色の混ぜ方を決めることが重要となる。

VkPipelineColorBlendStateCreateInfo

VkPipelineColorBlendStateCreateInfo - Structure specifying parameters of a newly created pipeline color blend state

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

  • flags is a bitmask of VkPipelineColorBlendStateCreateFlagBits specifying additional color blending information.
  • logicOpEnable controls whether to apply Logical Operations.
  • logicOp selects which logical operation to apply.
  • attachmentCount is the number of VkPipelineColorBlendAttachmentState elements in pAttachments.
  • pAttachments is a pointer to an array of VkPipelineColorBlendAttachmentState structures defining blend state for each color attachment.
  • blendConstants is a pointer to an array of four values used as the R, G, B, and A components of the blend constant that are used in blending, depending on the blend factor.

VkPipelineColorBlendStateCreateInfo(3)

flags

現状、設定できるパラメータは1種類だけのよう。

// Provided by VK_ARM_rasterization_order_attachment_access
typedef enum VkPipelineColorBlendStateCreateFlagBits {
  // Provided by VK_ARM_rasterization_order_attachment_access
    VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM = 0x00000001,
} VkPipelineColorBlendStateCreateFlagBits;

VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM indicates that access to color and input attachments will have implicit framebuffer-local memory dependencies, allowing applications to express custom blending operations in a fragment shader. See renderpass feedback loops for more information.
VkPipelineColorBlendStateCreateFlagBits(3)

内容が理解できないので、仕様書の拡張機能について書かれてある部分を見てみる。

VK_ARM_rasterization_order_attachment_access

Renderpasses, and specifically subpass self-dependencies enable much of the same functionality as the framebuffer fetch and pixel local storage extensions did for OpenGL ES. But certain techniques such as programmable blending are awkward or impractical to implement with these alone, in part because a self-dependency is required every time a fragment will read a value at a given sample coordinate.

This extension extends the mechanism of input attachments to allow access to framebuffer attachments when used as both input and color, or depth/stencil, attachments from one fragment to the next, in rasterization order, without explicit synchronization.
Vulkan® 1.2.203 - A Specification (with all registered Vulkan extensions)

「fragmentがsample coordinateを読み込む場合に、常に自己依存が要求されることもあり、programmable blendingのような技術をRenderpassesとspecifically subpass self-dependenciesだけで実装するのは、あまりよくない」とある。color blendingをprogrammableにするには、通常のrenderpassとsubpassだけでは足りないようだ。
そこでこの拡張機能では、input attachmentsとcolor or depth/stencial attachments)の両方が使用されている場合に、明示的なsynchroなしでinput attachmentがframebuffer attachmentにアクセスすることを可能にする、とある。

Feedback loops

If a subpass uses the same attachment as both an input attachment and either a color attachment or a depth/stencil attachment, writes via the color or depth/stencil attachment are not automatically made visible to reads via the input attachment, causing a feedback loop, except in any of the following conditions:
Vulkan® 1.2.203 - A Specification (with all registered Vulkan extensions)

subpassがinput attachmentとcolor or depth/stencial attachmentの両方を持つとき、color or depth/stencial attachmentからの書き込みは、input attachmentから自動的に読み込めるようにvisibleの状態にはならない、とある。そしてこれがfeedback loopを生み出すとある。

Rendering within a subpass containing a feedback loop creates a data race, except in the following cases:

  • If the attachment is used as color and input attachment, and the pipeline performing the read was created with VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM included in the flags member of the pColorBlendState member of its VkGraphicsPipelineCreateInfo. This creates a framebuffer-local memory dependency for each fragment generated by draw commands using this pipeline with the following properties:
    • The first synchronization scope includes the VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT pipeline stage executed by all previous fragments (as defined by primitive order) in the corresponding framebuffer regions including those generated by the same draw command.
    • The second synchronization scope includes the VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT pipeline stage executed by the generated fragment.
    • The first access scope includes all writes to color attachments.
    • The second access scope includes all reads from input attachments.

feedback loopsをもつsubpassでのrenderingではdata race(データ競合)が発生してしまうが、拡張機能を設定しておけば回避できる。拡張を設定することにより、各fragmentについてlocal memory依存のframebufferを作成できる。sync scopeとaccess scopeは書かれてある通りである。

logicOpEnable

The application can enable a logical operation between the fragment’s color values and the existing value in the framebuffer attachment. This logical operation is applied prior to updating the framebuffer attachment. Logical operations are applied only for signed and unsigned integer and normalized integer framebuffers. Logical operations are not applied to floating-point or sRGB format color attachments.
Vulkan® 1.2.203 - A Specification (with all registered Vulkan extensions)

logical operationsとは、fragmentの色とframe bufferに保存されている色の論理演算のことである。この演算はframe buffer attachmentが更新されるよりも前に行われる。logical operationsは整数型(signed, unsigned)のframe bufferにのみ適用される。
logicOpEnableはこの論理演算を行うかどうかを設定する。

logicOp

// Provided by VK_VERSION_1_0
typedef enum VkLogicOp {
    VK_LOGIC_OP_CLEAR = 0,
    VK_LOGIC_OP_AND = 1,
    VK_LOGIC_OP_AND_REVERSE = 2,
    VK_LOGIC_OP_COPY = 3,
    VK_LOGIC_OP_AND_INVERTED = 4,
    VK_LOGIC_OP_NO_OP = 5,
    VK_LOGIC_OP_XOR = 6,
    VK_LOGIC_OP_OR = 7,
    VK_LOGIC_OP_NOR = 8,
    VK_LOGIC_OP_EQUIVALENT = 9,
    VK_LOGIC_OP_INVERT = 10,
    VK_LOGIC_OP_OR_REVERSE = 11,
    VK_LOGIC_OP_COPY_INVERTED = 12,
    VK_LOGIC_OP_OR_INVERTED = 13,
    VK_LOGIC_OP_NAND = 14,
    VK_LOGIC_OP_SET = 15,
} VkLogicOp;
Mode Operation
VK_LOGIC_OP_CLEAR 0
VK_LOGIC_OP_AND s ∧ d
VK_LOGIC_OP_AND_REVERSE s ∧ ¬ d
VK_LOGIC_OP_COPY s
VK_LOGIC_OP_AND_INVERTED ¬ s ∧ d
VK_LOGIC_OP_NO_OP d
VK_LOGIC_OP_XOR s ⊕ d
VK_LOGIC_OP_OR s ∨ d
VK_LOGIC_OP_NOR ¬ (s ∨ d)
VK_LOGIC_OP_EQUIVALENT ¬ (s ⊕ d)
VK_LOGIC_OP_INVERT ¬ d
VK_LOGIC_OP_OR_REVERSE s ∨ ¬ d
VK_LOGIC_OP_COPY_INVERTED ¬ s
VK_LOGIC_OP_OR_INVERTED ¬ s ∨ d
VK_LOGIC_OP_NAND ¬ (s ∧ d)
VK_LOGIC_OP_SET all 1s
  • s is the fragment’s R_{s0}, G_{s0}, B_{s0} or A_{s0} component value for the fragment output corresponding to the color attachment being updated, and
  • d is the color attachment’s R, G, B or A component value

Vulkan® 1.2.203 - A Specification (with all registered Vulkan extensions)

pAttachments

VkPipelineColorBlendAttachmentState - Structure specifying a pipeline color blend attachment state

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

  • blendEnable controls whether blending is enabled for the corresponding color attachment. If blending is not enabled, the source fragment’s color for that attachment is passed through unmodified.
  • srcColorBlendFactor selects which blend factor is used to determine the source factors (Sr,Sg,Sb).
  • dstColorBlendFactor selects which blend factor is used to determine the destination factors (Dr,Dg,Db).
  • colorBlendOp selects which blend operation is used to calculate the RGB values to write to the color attachment.
  • srcAlphaBlendFactor selects which blend factor is used to determine the source factor Sa.
  • dstAlphaBlendFactor selects which blend factor is used to determine the destination factor Da.
  • alphaBlendOp selects which blend operation is use to calculate the alpha values to write to the color attachment.
  • colorWriteMask is a bitmask of VkColorComponentFlagBits specifying which of the R, G, B, and/or A components are enabled for writing, as described for the Color Write Mask.

VkPipelineColorBlendAttachmentState(3)

blendEnable

color blendingを実行するかどうかを決める。

srcColorBlendFactor

VkBlendFactor - Framebuffer blending factors

// Provided by VK_VERSION_1_0
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;
VkBlendFactor RGB Blend Factors (Sr,Sg,Sb) or (Dr,Dg,Db) Alpha Blend Factor (Sa or Da)
VK_BLEND_FACTOR_ZERO (0,0,0) 0
VK_BLEND_FACTOR_ONE (1,1,1) 1
VK_BLEND_FACTOR_SRC_COLOR (Rs0,Gs0,Bs0) As0
VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR (1-Rs0,1-Gs0,1-Bs0) 1-As0
VK_BLEND_FACTOR_DST_COLOR (Rd,Gd,Bd) Ad
VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR (1-Rd,1-Gd,1-Bd) 1-Ad
VK_BLEND_FACTOR_SRC_ALPHA (As0,As0,As0) As0
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA (1-As0,1-As0,1-As0) 1-As0
VK_BLEND_FACTOR_DST_ALPHA (Ad,Ad,Ad) Ad
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA (1-Ad,1-Ad,1-Ad) 1-Ad
VK_BLEND_FACTOR_CONSTANT_COLOR (Rc,Gc,Bc) Ac
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR (1-Rc,1-Gc,1-Bc) 1-Ac
VK_BLEND_FACTOR_CONSTANT_ALPHA (Ac,Ac,Ac) Ac
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA (1-Ac,1-Ac,1-Ac) 1-Ac
VK_BLEND_FACTOR_SRC_ALPHA_SATURATE (f,f,f); f = min(As0,1-Ad) 1
VK_BLEND_FACTOR_SRC1_COLOR (Rs1,Gs1,Bs1) As1
VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR (1-Rs1,1-Gs1,1-Bs1) 1-As1
VK_BLEND_FACTOR_SRC1_ALPHA (As1,As1,As1) As1
VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA (1-As1,1-As1,1-As1) 1-As1

R_{s0},G_{s0},B_{s0} and A_{s0} represent the first source color R, G, B, and A components
R_{s1},G_{s1},B_{s1} and A_{s1} represent the second source color R, G, B, and A components, used in dual source blending modes
R_d,G_d,B_d and A_d represent the R, G, B, and A components of the destination color
R_c,G_c,B_c and A_c represent the blend constant R, G, B, and A components

VkBlendFactor(3)
source colorとして何を指定するのかを入力する。

colorBlendOp
// Provided by VK_VERSION_1_0
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;

VK_EXT_blend_operation_advancedの拡張機能を指定すれば、さらに多くのオプションを選べるようになる。
VkBlendOp(3)
それぞれのblendOpによる計算は以下の通り。

VkBlendOp RGB Components Alpha Component
VK_BLEND_OP_ADD R = R_{s0} × S_r + R_d × D_r
G = G_{s0} × S_g + G_d × D_g
B = B_{s0} × S_b + B_d × D_b
A = A_{s0} × S_a + A_d × D_a
VK_BLEND_OP_SUBTRACT R = R_{s0} × S_r - R_d × D_r
G = G_{s0} × S_g - G_d × D_g
B = B_{s0} × S_b - B_d × D_b
A = A_{s0} × S_a - A_d × D_a
VK_BLEND_OP_REVERSE_SUBTRACT R = R_d × D_r - R_{s0} × S_r
G = G_d × D_g - G_{s0} × S_g
B = B_d × D_b - B_{s0} × S_b
A = A_d × D_a - A_{s0} × 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)

出典 : Table 1. Basic Blend OperationsVkBlendOp(3)
S : Source Blend Factor
D : Destination Blend Facror

colorWriteMask

VkColorComponentFlagBits - Bitmask controlling which components are written to the framebuffer
Bits which can be set in VkPipelineColorBlendAttachmentState::colorWriteMask to determine whether the final color values R, G, B and A are written to the framebuffer attachment are:

// Provided by VK_VERSION_1_0
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;

The color write mask operation is applied regardless of whether blending is enabled.
VkColorComponentFlagBits(3)

color maskはどの色が最終的にframe bufferに格納されるかを決める。color maskはblendEnableの値に依らず参照される。もしmaskが指定されていなければ、frame bufferの値は更新されない。

blendConstants

srcColorBlendFactorの欄であるように、constant colorの値を指定する。