Pipeline state configuration

DSHL has some state variables that are used for configuring fixed pipeline stages (blending, depth/stencil testing, etc.). You can optionally define them inside a shader.

Blending

Blending settings can be configured in DSHL shader using the following syntax:

blend_target = blend_factor;

where blend_target is one of these state variables

  • blend_src – blend source

  • blend_dst – blend destination

  • blend_asrc – blend alpha source

  • blend_adst – blend alpha destination

and blend_factor is one of these keywords:

Keyword

Description

RGB Blend Factor

Alpha Blend Factor

zero or 0

Zero

(0, 0, 0)

0

one or 1

One

(1, 1, 1)

1

sc

Source Color

(R_s, G_s, B_s)

A_s

isc

Inverse Source Color

(1 - R_s, 1 - G_s, 1 - B_s)

1 - A_s

sa

Source Alpha

(A_s, A_s, A_s)

A_s

isa

Inverse Source Alpha

(1 - A_s, 1 - A_s, 1 - A_s)

1 - A_s

dc

Destination Color

(R_d, G_d, B_d)

A_d

idc

Inverse Destination Color

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

1 - A_d

da

Destination Alpha

(A_d, A_d, A_d)

A_d

ida

Inverse Destination Alpha

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

1 - A_d

sasat

Source Alpha Saturation

(f, f, f); f = min(A_s, 1 - A_d)

1

bf

Blend Constant

(R_c, G_c, B_c)

A_c

ibf

Inverse Blend Constant

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

1 - A_c

where

  • (R_s, G_s, B_s) and A_s represent R, G, B, A components of the source (new value which shader just produced)

  • (R_d, G_d, B_d) and A_d represent R, G, B, A components of the destination (old value in the current render target)

  • (R_c, G_c, B_c) and A_c represent configurable blend constants

Blending is performed using the following pseudocode:

  if (blendEnable) {
    finalColor.rgb = (srcColorBlendFactor * srcColor.rgb) <colorBlendOp> (dstColorBlendFactor * dstColor.rgb);
    finalColor.a = (srcAlphaBlendFactor * srcColor.a) <alphaBlendOp> (dstAlphaBlendFactor * dstColor.a);
  } else {
    finalColor = srcColor;
  }

finalColor = finalColor & colorWriteMask;

Example:

blend_src = sa; blend_dst = 1;
blend_asrc = sa; blend_adst = 1;

Warning

Blend constants for the bf and ibf factors still need to be configured in C++ code. Blend operations, however, can be set directly in DSHL – see Blend operation below.

If you don’t configure blending factors in the shader, these defaults will be used:

blend_src = 1; blend_dst = 0;
blend_asrc = 1; blend_adst = 0;

Blend operation

The weighted source and destination values are combined with a blend operation – the <colorBlendOp> / <alphaBlendOp> in the pseudocode above. By default this is addition; it can be changed with these state variables:

  • blend_op – RGB blend operation

  • blend_aop – alpha blend operation

Each accepts one of the following operations:

  • addsrc + dst (default)

  • minmin(src, dst)

  • maxmax(src, dst)

Example (max blending):

blend_src = 1; blend_dst = 1;
blend_op  = max;

Note

Only add, min and max are exposed in DSHL. The hardware subtract / revsubtract operations are not available here.

If you don’t set an operation, it defaults to add.

Important

blend_op and blend_aop only have an effect when blending is enabled for the target, i.e. when its blend_src and blend_dst factors are set.

blend_aop additionally requires separate alpha blending, which is turned on by setting the separate alpha factors blend_asrc and blend_adstnot by setting blend_aop itself. If the separate alpha factors are not set, the alpha channel reuses the color operation blend_op, and blend_aop (including its add default) is ignored.

So, with blending enabled, setting only blend_op = max (no blend_aop, no separate alpha factors) makes both color and alpha blend with max. To give alpha a different operation you must also set blend_asrc / blend_adst.

Like blend factors, blend_op / blend_aop can be indexed per render target for independent blending (see below).

Warning

Dual-source blending (the sc1 / isc1 / sa1 / isa1 factors) only supports the add blend operation.

Independent blending

Dagor supports independent blending, i.e. different render targets may have different blending settings. This is done by providing an index to blend_src, blend_dst, blend_asrc, blend_adst, blend_op, blend_aop variables with [] operator.

blend_src[0] = 1; blend_dst[0] = 0;
blend_src[1] = 0; blend_dst[1] = 1;

Without an index, the value affects all render targets.

Depth/Stencil

Depth and stencil tests can also be configured in DSHL using similar syntax.

Depth state variables

z_write – enables/disables writing to depth buffer. Valid values: true / false. Default value: true.

z_test – enables/disables depth testing. Valid values: true / false. Default value: true.

z_func – specifies comparison function for depth testing. Valid values:

  • equal evaluates to \(\text{reference} = \text{test}\)

  • notequal evaluates to \(\text{reference} \neq \text{test}\)

  • always always evaluates to true

Default value is GREATER_OR_EQUAL (evaluates to \(\text{reference} \geq \text{test}\)). Note that this value cannot be set explicitly, as it is the default behavior, because Dagor follows the convention that closer objects have more depth value.

Example:

z_write = false;
z_test = true;
z_func = always;

Stencil state variables

stencil – enables/disables stencil test. Valid values: true / false. Default value: false.

stencil_func – specifies comparison function for stencil testing. Valid values:

  • never always evaluates to false

  • less evaluates to \(\text{reference} < \text{test}\)

  • equal evaluates to \(\text{reference} = \text{test}\)

  • lessequal evaluates to \(\text{reference} \leq \text{test}\)

  • greater evaluates to \(\text{reference} > \text{test}\)

  • notequal evaluates to \(\text{reference} \neq \text{test}\)

  • greaterequal evaluates to \(\text{reference} \geq \text{test}\)

  • always always evaluates to true

stencil_ref – specifies reference value for the stencil test. Valid values: int, clamped to [0, 255] range.

stencil_pass – specifies the action performed on samples that pass both stencil and depth tests.

stencil_fail – specifies the action performed on samples that fail the stencil test.

stencil_zfail – specifies the action performed on samples that pass the stencil test and fail the depth test.

Valid actions:

  • keep – keeps the current value.

  • zero – sets the value to 0.

  • replace – sets the value to reference stencil_ref value

  • incrsat – increments the current value and clamps to [0, 255]

  • decrsat – decrements the current value and clamps to [0, 255]

  • incr – increments the current value and wraps to 0 when the maximum value would have been exceeded.

  • decr – decrements the current value and wraps to 255 the maximum possible value when the value would go below 0.

Example:

stencil = true;
stencil_func = always;
stencil_pass = replace;
stencil_ref = 255;
stencil_zfail = keep;
stencil_fail = keep;

Culling

cull_mode specifies culling mode.

  • ccw – counterclockwise.

  • cw – clockwise.

  • none – no culling is done.

Default value is ccw.

Example:

cull_mode = cw;

Alpha to coverage

Alpha to coverage (A2C) maps the alpha output value from a pixel shader to the coverage mask of MSAA. This feature might be helpful for smoothing out the edges of alpha-tested texture (e.g. vegetation).

For example, with 4x MSAA and A2C enabled, if the output alpha of a pixel is 0.5, only 2 of the 4 coverage samples will store the color.

Can be toggled by setting alpha_to_coverage to true / false.

View instancing

View instancing feature allows a shader to be run multiple times in a single draw call to draw different view instances. The SV_ViewID semantic is provided to the shader which defines the index of the view instance. This feature is supported only on DX12 and enforces Shader Model 6.1 compilation.

Maximum number of view instances is defined by MAX_VIEW_INSTANCES = 4. For example, using view instancing, you can capture a cube shadow map for a point light in 2 render passes with 3 view instances per pass.

Valid syntax is view_instances = 1..4.

view_instances = 1 means one instance (which is the default case).

Color write mask

Color write mask can be configured with color_write state variable. You can set the mask via RGBA swizzle or by an int number (in [0, 15] range). So r = 0b0001, g = 0b0010, b = 0b0100, a = 0b1000.

For example,

color_write = rg;
// color_write = 3 is the same
// 3 = 0b0011 = rg

Color mask supports multiple render targets, i.e. for each render target the mask can be different. You can use [] operator to specify the mask for the specific render target.

color_write = true; // sets RGBA for all RT
color_write[1] = rg; // sets RG for RT[1]

By default, color mask is RGBA for all render targets.