Skip to content

Latest commit

 

History

History
2338 lines (1920 loc) · 101 KB

fragops.adoc

File metadata and controls

2338 lines (1920 loc) · 101 KB

Fragment Operations

Fragments produced by rasterization go through a number of operations to determine whether or how values produced by fragment shading are written to the framebuffer.

The following fragment operations adhere to rasterization order, and are typically performed in this order:

The coverage mask generated by rasterization describes the initial coverage of each sample covered by the fragment. Fragment operations will update the coverage mask to add or subtract coverage where appropriate. If a fragment operation results in all bits of the coverage mask being 0, the fragment is discarded, and no further operations are performed. Fragments can also be programmatically discarded in a fragment shader by executing one of

  • code:OpKill.

When one of the fragment operations in this chapter is described as “replacing” a fragment shader output, that output is replaced unconditionally, even if no fragment shader previously wrote to that output.

If there is a fragment shader and it declares the code:EarlyFragmentTests execution mode, fragment shading and multisample coverage operations should: instead be performed after sample counting, and sample mask test may: instead be performed after sample counting.

For a pipeline with the following properties:

  • a fragment shader is specified

  • the fragment shader does not write to storage resources;

  • the fragment shader specifies the code:DepthReplacing execution mode; and

  • either

    • the fragment shader specifies the code:DepthUnchanged execution mode;

    • the fragment shader specifies the code:DepthGreater execution mode and the pipeline uses a slink:VkPipelineDepthStencilStateCreateInfo::pname:depthCompareOp of ename:VK_COMPARE_OP_GREATER or ename:VK_COMPARE_OP_GREATER_OR_EQUAL; or

    • the fragment shader specifies the code:DepthLess execution mode and the pipeline uses a slink:VkPipelineDepthStencilStateCreateInfo::pname:depthCompareOp of ename:VK_COMPARE_OP_LESS or ename:VK_COMPARE_OP_LESS_OR_EQUAL

the implementation may: perform depth bounds test before fragment shading and perform an additional depth test immediately after that using the interpolated depth value generated by rasterization.

Once all fragment operations have completed, fragment shader outputs for covered color attachment samples pass through framebuffer operations.

Scissor Test

The scissor test compares the framebuffer coordinates (xf,yf) of each sample covered by a fragment against a scissor rectangle at the index equal to the fragment’s code:ViewportIndex.

Each scissor rectangle is defined by a slink:VkRect2D. These values are either set by the slink:VkPipelineViewportStateCreateInfo structure during pipeline creation, or dynamically by the flink:vkCmdSetScissor command.

A given sample is considered inside a scissor rectangle if xf is in the range [slink:VkRect2D::pname:offset.x, slink:VkRect2D::pname:offset.x + slink:VkRect2D::pname:extent.x), and yf is in the range [slink:VkRect2D::pname:offset.y, slink:VkRect2D::pname:offset.y + slink:VkRect2D::pname:extent.y). Samples with coordinates outside the scissor rectangle at the corresponding code:ViewportIndex will have their coverage set to 0.

To dynamically set the scissor rectangles, call:

  • pname:commandBuffer is the command buffer into which the command will be recorded.

  • pname:firstScissor is the index of the first scissor whose state is updated by the command.

  • pname:scissorCount is the number of scissors whose rectangles are updated by the command.

  • pname:pScissors is a pointer to an array of slink:VkRect2D structures defining scissor rectangles.

The scissor rectangles taken from element i of pname:pScissors replace the current state for the scissor index pname:firstScissor + i, for i in [0, pname:scissorCount).

This command sets the scissor rectangles for subsequent drawing commands when the graphics pipeline is created with ename:VK_DYNAMIC_STATE_SCISSOR set in slink:VkPipelineDynamicStateCreateInfo::pname:pDynamicStates. Otherwise, this state is specified by the slink:VkPipelineViewportStateCreateInfo::pname:pScissors values used to create the currently active pipeline.

Valid Usage
  • The sum of pname:firstScissor and pname:scissorCount must: be between 1 and sname:VkPhysicalDeviceLimits::pname:maxViewports, inclusive

  • If the pname:multiViewport feature is not enabled, pname:firstScissor must: be 0

  • If the pname:multiViewport feature is not enabled, pname:scissorCount must: be 1

  • The pname:x and pname:y members of pname:offset member of any element of pname:pScissors must: be greater than or equal to 0

  • Evaluation of (pname:offset.x + pname:extent.width) must: not cause a signed integer addition overflow for any element of pname:pScissors

  • Evaluation of (pname:offset.y + pname:extent.height) must: not cause a signed integer addition overflow for any element of pname:pScissors

Sample Mask Test

The sample mask test compares the coverage mask for a fragment with the sample mask defined by slink:VkPipelineMultisampleStateCreateInfo::pname:pSampleMask.

Each bit of the coverage mask is associated with a sample index as described in the rasterization chapter. If the bit in slink:VkPipelineMultisampleStateCreateInfo::pname:pSampleMask which is associated with that same sample index is set to 0, the coverage mask bit is set to 0.

Fragment Shading

Fragment shaders are invoked for each fragment, or as helper invocations.

Most operations in the fragment shader are not performed in rasterization order, with exceptions called out in the following sections.

For fragment shaders invoked by fragments, the following rules apply:

  • A fragment shader must: not be executed if a fragment operation that executes before fragment shading discards the fragment.

  • A fragment shader may: not be executed if:

    • An implementation determines that another fragment shader, invoked by a subsequent primitive in primitive order, overwrites all results computed by the shader (including writes to storage resources).

    • Any other fragment operation discards the fragment, and the shader does not write to any storage resources.

  • Otherwise, at least one fragment shader must: be executed.

    • If sample shading is enabled and multiple invocations per fragment are required:, additional invocations must: be executed as specified.

    • Each covered sample must: be included in at least one fragment shader invocation.

If no fragment shader is included in the pipeline, no fragment shader is executed, and undefined: values may: be written to all color attachment outputs during this fragment operation.

Note
Note

Multiple fragment shader invocations may be executed for the same fragment for any number of implementation-dependent reasons. When there is more than one fragment shader invocation per fragment, the association of samples to invocations is implementation-dependent. Stores and atomics performed by these additional invocations have the normal effect.

Sample Mask

Reading from the code:SampleMask built-in in the code:Input storage class will return the coverage mask for the current fragment as calculated by fragment operations that executed prior to fragment shading.

If sample shading is enabled, fragment shaders will only see values of 1 for samples being shaded - other bits will be 0.

Each bit of the coverage mask is associated with a sample index as described in the rasterization chapter. If the bit in code:SampleMask which is associated with that same sample index is set to 0, that coverage mask bit is set to 0.

Values written to the code:SampleMask built-in in the code:Output storage class will be used by the multisample coverage operation, with the same encoding as the input built-in.

Depth Replacement

Writing to the code:FragDepth built-in will replace the fragment’s calculated depth values for each sample in the input code:SampleMask. Depth testing performed after the fragment shader for this fragment will use this new value as zf.

Multisample Coverage

If a fragment shader is active and its entry point’s interface includes a built-in output variable decorated with code:SampleMask, the coverage mask is code:ANDed with the bits of the code:SampleMask built-in to generate a new coverage mask. If sample shading is enabled, bits written to code:SampleMask corresponding to samples that are not being shaded by the fragment shader invocation are ignored. If no fragment shader is active, or if the active fragment shader does not include code:SampleMask in its interface, the coverage mask is not modified.

Next, the fragment alpha value and coverage mask are modified based on the pname:alphaToCoverageEnable and pname:alphaToOneEnable members of the slink:VkPipelineMultisampleStateCreateInfo structure.

All alpha values in this section refer only to the alpha component of the fragment shader output that has a code:Location and code:Index decoration of zero (see the Fragment Output Interface section). If that shader output has an integer or unsigned integer type, then these operations are skipped.

If pname:alphaToCoverageEnable is enabled, a temporary coverage mask is generated where each bit is determined by the fragment’s alpha value, which is ANDed with the fragment coverage mask.

No specific algorithm is specified for converting the alpha value to a temporary coverage mask. It is intended that the number of 1’s in this value be proportional to the alpha value (clamped to [0,1]), with all 1’s corresponding to a value of 1.0 and all 0’s corresponding to 0.0. The algorithm may: be different at different framebuffer coordinates.

Note
Note

Using different algorithms at different framebuffer coordinates may: help to avoid artifacts caused by regular coverage sample locations.

Finally, if pname:alphaToOneEnable is enabled, each alpha value is replaced by the maximum representable alpha value for fixed-point color attachments, or by 1.0 for floating-point attachments. Otherwise, the alpha values are not changed.

Depth and Stencil Operations

Pipeline state controlling the depth bounds tests, stencil test, and depth test is specified through the members of the sname:VkPipelineDepthStencilStateCreateInfo structure.

The sname:VkPipelineDepthStencilStateCreateInfo structure is defined as:

  • pname:sType is the type of this structure.

  • pname:pNext is NULL or a pointer to a structure extending this structure.

  • pname:flags is reserved for future use.

  • pname:depthTestEnable controls whether depth testing is enabled.

  • pname:depthWriteEnable controls whether depth writes are enabled when pname:depthTestEnable is ename:VK_TRUE. Depth writes are always disabled when pname:depthTestEnable is ename:VK_FALSE.

  • pname:depthCompareOp is a elink:VkCompareOp value specifying the comparison operator to use in the Depth Comparison step of the depth test.

  • pname:depthBoundsTestEnable controls whether depth bounds testing is enabled.

  • pname:stencilTestEnable controls whether stencil testing is enabled.

  • pname:front and pname:back are slink:VkStencilOpState values controlling the corresponding parameters of the stencil test.

  • pname:minDepthBounds is the minimum depth bound used in the depth bounds test.

  • pname:maxDepthBounds is the maximum depth bound used in the depth bounds test.

Valid Usage
  • If the pname:depthBounds feature is not enabled, pname:depthBoundsTestEnable must: be ename:VK_FALSE

tname:VkPipelineDepthStencilStateCreateFlags is a bitmask type for setting a mask, but is currently reserved for future use.

Depth Bounds Test

The depth bounds test compares the depth value za in the depth/stencil attachment at each sample’s framebuffer coordinates (xf,yf) and sample index i against a set of depth bounds.

The depth bounds are determined by two floating point values defining a minimum (pname:minDepthBounds) and maximum (pname:maxDepthBounds) depth value. These values are either set by the slink:VkPipelineDepthStencilStateCreateInfo structure during pipeline creation, or dynamically by flink:vkCmdSetDepthBounds.

A given sample is considered within the depth bounds if za is in the range [pname:minDepthBounds,pname:maxDepthBounds]. Samples with depth attachment values outside of the depth bounds will have their coverage set to 0.

If the depth bounds test is disabled, or if there is no depth attachment, the coverage mask is unmodified by this operation.

To dynamically set the depth bounds range, call:

  • pname:commandBuffer is the command buffer into which the command will be recorded.

  • pname:minDepthBounds is the minimum depth bound.

  • pname:maxDepthBounds is the maximum depth bound.

This command sets the depth bounds range for subsequent drawing commands when the graphics pipeline is created with ename:VK_DYNAMIC_STATE_DEPTH_BOUNDS set in slink:VkPipelineDynamicStateCreateInfo::pname:pDynamicStates. Otherwise, this state is specified by the slink:VkPipelineDepthStencilStateCreateInfo::pname:minDepthBounds and slink:VkPipelineDepthStencilStateCreateInfo::pname:maxDepthBounds values used to create the currently active pipeline.

Valid Usage
  • pname:minDepthBounds must: be between 0.0 and 1.0, inclusive

  • pname:maxDepthBounds must: be between 0.0 and 1.0, inclusive

Stencil Test

The stencil test compares the stencil attachment value sa in the depth/stencil attachment at each sample’s framebuffer coordinates (xf,yf) and sample index i against a stencil reference value.

If the stencil test is not enabled, as specified by slink:VkPipelineDepthStencilStateCreateInfo::pname:stencilTestEnable, or if there is no stencil attachment, the coverage mask is unmodified by this operation.

The stencil test is controlled by one of two sets of stencil-related state, the front stencil state and the back stencil state. Stencil tests and writes use the back stencil state when processing fragments generated by back-facing polygons, and the front stencil state when processing fragments generated by front-facing polygons or any other primitives.

The comparison operation performed is determined by the elink:VkCompareOp value set by slink:VkStencilOpState::pname:compareOp during pipeline creation.

The compare mask sc and stencil reference value sr of the front or the back stencil state set determine arguments of the comparison operation. sc is set by the slink:VkPipelineDepthStencilStateCreateInfo structure during pipeline creation, or by the flink:vkCmdSetStencilCompareMask command. sr is set by slink:VkPipelineDepthStencilStateCreateInfo or by flink:vkCmdSetStencilReference.

sr and sa are each independently combined with sc using a bitwise code:AND operation to create masked reference and attachment values s'r and s'a. s'r and s'a are used as the reference and test values, respectively, in the operation specified by the elink:VkCompareOp.

If the comparison evaluates to false, the coverage for the sample is set to 0.

A new stencil value sg is generated according to a stencil operation defined by elink:VkStencilOp parameters set by slink:VkPipelineDepthStencilStateCreateInfo. If the stencil test fails, pname:failOp defines the stencil operation used. If the stencil test passes however, the stencil op used is based on the depth test - if it passes, slink:VkPipelineDepthStencilStateCreateInfo::pname:passOp is used, otherwise slink:VkPipelineDepthStencilStateCreateInfo::pname:depthFailOp is used.

The stencil attachment value sa is then updated with the generated stencil value sg according to the write mask sw defined by pname:writeMask in slink:VkPipelineDepthStencilStateCreateInfo::pname:front and slink:VkPipelineDepthStencilStateCreateInfo::pname:back as:

sa = (sa & ¬sw) | (sg & sw)

The sname:VkStencilOpState structure is defined as:

  • pname:failOp is a elink:VkStencilOp value specifying the action performed on samples that fail the stencil test.

  • pname:passOp is a elink:VkStencilOp value specifying the action performed on samples that pass both the depth and stencil tests.

  • pname:depthFailOp is a elink:VkStencilOp value specifying the action performed on samples that pass the stencil test and fail the depth test.

  • pname:compareOp is a elink:VkCompareOp value specifying the comparison operator used in the stencil test.

  • pname:compareMask selects the bits of the unsigned integer stencil values participating in the stencil test.

  • pname:writeMask selects the bits of the unsigned integer stencil values updated by the stencil test in the stencil framebuffer attachment.

  • pname:reference is an integer stencil reference value that is used in the unsigned stencil comparison.

To dynamically set the stencil compare mask, call:

  • pname:commandBuffer is the command buffer into which the command will be recorded.

  • pname:faceMask is a bitmask of elink:VkStencilFaceFlagBits specifying the set of stencil state for which to update the compare mask.

  • pname:compareMask is the new value to use as the stencil compare mask.

This command sets the stencil compare mask for subsequent drawing commands when the graphics pipeline is created with ename:VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK set in slink:VkPipelineDynamicStateCreateInfo::pname:pDynamicStates. Otherwise, this state is specified by the slink:VkStencilOpState::pname:compareMask value used to create the currently active pipeline, for both front and back faces.

ename:VkStencilFaceFlagBits values are:

  • ename:VK_STENCIL_FACE_FRONT_BIT specifies that only the front set of stencil state is updated.

  • ename:VK_STENCIL_FACE_BACK_BIT specifies that only the back set of stencil state is updated.

  • ename:VK_STENCIL_FACE_FRONT_AND_BACK is the combination of ename:VK_STENCIL_FACE_FRONT_BIT and ename:VK_STENCIL_FACE_BACK_BIT, and specifies that both sets of stencil state are updated.

tname:VkStencilFaceFlags is a bitmask type for setting a mask of zero or more elink:VkStencilFaceFlagBits.

To dynamically set the stencil write mask, call:

  • pname:commandBuffer is the command buffer into which the command will be recorded.

  • pname:faceMask is a bitmask of elink:VkStencilFaceFlagBits specifying the set of stencil state for which to update the write mask, as described above for flink:vkCmdSetStencilCompareMask.

  • pname:writeMask is the new value to use as the stencil write mask.

This command sets the stencil write mask for subsequent drawing commands when the graphics pipeline is created with ename:VK_DYNAMIC_STATE_STENCIL_WRITE_MASK set in slink:VkPipelineDynamicStateCreateInfo::pname:pDynamicStates. Otherwise, this state is specified by the pname:writeMask value used to create the currently active pipeline, for both slink:VkPipelineDepthStencilStateCreateInfo::pname:front and slink:VkPipelineDepthStencilStateCreateInfo::pname:back faces.

To dynamically set the stencil reference value, call:

  • pname:commandBuffer is the command buffer into which the command will be recorded.

  • pname:faceMask is a bitmask of elink:VkStencilFaceFlagBits specifying the set of stencil state for which to update the reference value, as described above for flink:vkCmdSetStencilCompareMask.

  • pname:reference is the new value to use as the stencil reference value.

This command sets the stencil reference value for subsequent drawing commands when the graphics pipeline is created with ename:VK_DYNAMIC_STATE_STENCIL_REFERENCE set in slink:VkPipelineDynamicStateCreateInfo::pname:pDynamicStates. Otherwise, this state is specified by the slink:VkPipelineDepthStencilStateCreateInfo::pname:reference value used to create the currently active pipeline, for both front and back faces.

Possible values of the pname:failOp, pname:passOp, and pname:depthFailOp members of slink:VkStencilOpState, specifying what happens to the stored stencil value if this or certain subsequent tests fail or pass, are:

  • ename:VK_STENCIL_OP_KEEP keeps the current value.

  • ename:VK_STENCIL_OP_ZERO sets the value to 0.

  • ename:VK_STENCIL_OP_REPLACE sets the value to pname:reference.

  • ename:VK_STENCIL_OP_INCREMENT_AND_CLAMP increments the current value and clamps to the maximum representable unsigned value.

  • ename:VK_STENCIL_OP_DECREMENT_AND_CLAMP decrements the current value and clamps to 0.

  • ename:VK_STENCIL_OP_INVERT bitwise-inverts the current value.

  • ename:VK_STENCIL_OP_INCREMENT_AND_WRAP increments the current value and wraps to 0 when the maximum value would have been exceeded.

  • ename:VK_STENCIL_OP_DECREMENT_AND_WRAP decrements the current value and wraps to the maximum possible value when the value would go below 0.

For purposes of increment and decrement, the stencil bits are considered as an unsigned integer.

Depth Test

The depth test compares the depth value za in the depth/stencil attachment at each sample’s framebuffer coordinates (xf,yf) and sample index i against the sample’s depth value zf. If there is no depth attachment then the depth test is skipped.

The depth test occurs in three stages, as detailed in the following sections.

Depth Clamping and Range Adjustment

If slink:VkPipelineRasterizationStateCreateInfo::pname:depthClampEnable is enabled, zf is clamped to [zmin, zmax], where zmin = min(n,f), zmax = max(n,f)], and n and f are the pname:minDepth and pname:maxDepth depth range values of the viewport used by this fragment, respectively.

Following depth clamping:

  • If zf is not in the range [zmin, zmax], then zf is undefined: following this step.

Depth Comparison

If the depth test is not enabled, as specified by slink:VkPipelineDepthStencilStateCreateInfo::pname:depthTestEnable, then this step is skipped.

The comparison operation performed is determined by the elink:VkCompareOp value set by slink:VkPipelineDepthStencilStateCreateInfo::pname:depthCompareOp during pipeline creation. zf and za are used as the reference and test values, respectively, in the operation specified by the elink:VkCompareOp.

If the comparison evaluates to false, the coverage for the sample is set to 0.

Depth Attachment Writes

If depth writes are enabled, as specified by slink:VkPipelineDepthStencilStateCreateInfo::pname:depthWriteEnable, and the comparison evaluated to true, the depth attachment value za is set to the sample’s depth value zf. If there is no depth attachment, no value is written.

Sample Counting

Occlusion queries use query pool entries to track the number of samples that pass all the per-fragment tests. The mechanism of collecting an occlusion query value is described in Occlusion Queries.

The occlusion query sample counter increments by one for each sample with a coverage value of 1 in each fragment that survives all the per-fragment tests, including scissor, sample mask, alpha to coverage, stencil, and depth tests.

Coverage Reduction

Coverage reduction takes the coverage information for a fragment and converts that to a boolean coverage value for each color sample in each pixel covered by the fragment.

Pixel Coverage

Coverage for each pixel is first extracted from the total fragment coverage mask. This consists of pname:rasterizationSamples unique coverage samples for each pixel in the fragment area, each with a unique sample index. If the fragment only contains a single pixel, coverage for the pixel is equivalent to the fragment coverage.

Color Sample Coverage

Once pixel coverage is determined, coverage for each individual color sample corresponding to that pixel is determined.

The number of pname:rasterizationSamples is identical to the number of samples in the color attachments. A color sample is covered if the pixel coverage sample with the same sample index i is covered.