这是indexloc提供的服务,不要输入任何密码
Skip to content

Investigation: Rasterization State #137

@Richard-Yunchao

Description

@Richard-Yunchao

Introduction

There are a few widely used features that can impact rasterization fixed-function stage, for example, back face culling and front/back facing definition (ccw or cw), depth clip or clamp, rasterization discard, triangle fill mode, wide lines, etc. D3D12 and Vulkan have a standalone descriptor called rasterization descriptor/state to config these parameters in its graphics pipeline descriptor/state, and Metal can also set these parameters via some functions.

This document attempts to describe these features among three native graphics APIs, in order to discuss some missing features in WebGPU idl.

This document was updated/corrected according to comments below.

Native APIs

D3D12

D3D12 has a descriptor named RASTERIZER_DESC. Its definition is listed as follow:

typedef struct D3D12_RASTERIZER_DESC {
  D3D12_FILL_MODE                       FillMode;
  D3D12_CULL_MODE                       CullMode;
  BOOL                                  FrontCounterClockwise;
  INT                                   DepthBias;
  FLOAT                                 DepthBiasClamp;
  FLOAT                                 SlopeScaledDepthBias;
  BOOL                                  DepthClipEnable;
  BOOL                                  MultisampleEnable;
  BOOL                                  AntialiasedLineEnable;
  UINT                                  ForcedSampleCount;
  D3D12_CONSERVATIVE_RASTERIZATION_MODE ConservativeRaster;
} D3D12_RASTERIZER_DESC;

Triangle Fill Mode

Triangle Fill Mode is used to specify that we draw 1) a solid triangle, or 2) only line/wireframe of the triangle, or 3) only point/vertex of the triangle. The advantage of triangle fill mode is that some operations like back-face culling can be used upon triangles with line or point fill mode. But if you draw lines or points directly, these features don't take effect because they operate only on complete triangles.

D3D12 has a parameter FillMode to config this feature. The options are fill (solid) and line (wireframe), see the definition of FILL_MODE below:

typedef enum D3D12_FILL_MODE {
  D3D12_FILL_MODE_WIREFRAME,
  D3D12_FILL_MODE_SOLID
} ;

Front Face and Cull Mode

Front Face is used to specify which direction a triangle is facing via its winding order. Typically it uses counterclockwise (ccw) or clockwise(cw) to determine its front face, and the other winding order(cw or ccw) is back face. Once the direction of a triangle is determined, Cull Mode is used to specify a particular direction that a triangle falls to the specified direction will be culled and discarded. The typical options are none, back face, and front face.

Front Face: D3D12 has a parameter FrontCounterClockwise to config this feature. If this member is TRUE, a triangle will be considered front-facing if its vertices are counter-clockwise on the render target and considered back-facing if they are clockwise. If this parameter is FALSE, the opposite is true.

Cull Mode: D3D12 has a parameter CullMode to cull and discard triangles whose facing fall into the specified facing. CullMode has a few enumerations: none, front, and back. They are grouped into CULL_MODE and listed as follow.

typedef enum D3D12_CULL_MODE {
  D3D12_CULL_MODE_NONE,
  D3D12_CULL_MODE_FRONT,
  D3D12_CULL_MODE_BACK
} ;

Depth Clip or Clamp

Depth Clip is used to clip the depth value (z value). If the x or y coordinate of a vertex is outside of the view volume, it will be clipped away by default. But whether we clip a vertex whose z coordinate (depth) is outside of the view volume (near plane and far plane for depth) depends on this parameter. If depth clip is enabled, that vertex will be clipped away. If it is disabled, that vertex will be retained and drawn. The latter can be used to fill holes in geometry that would be caused by clipping. It is also called Depth Clamp, because it looks like the near and far planes are ignored and depth values are clamped to infinite near and far planes.

D3D12 has a parameter DepthClipEnable, which can be true or false in order to enable or disable depth clip.

Rasterization Discard

Both Metal and Vulkan can discard rasterization, which will stop the current pipeline before rasterization. D3D12 can support Stream Output, by which you can retrieve the geometry information right before rasterization and discard rasterization and all other stages afterwards. If this feature is enabled, it will enable rasterization discard implicitly.

However, I didn't find any parameter to explicitly enable/disable rasterization discard in D3D. Please correct me if I am wrong.

(Updated according the comments below) We can enable rasterization discard via empty pixel shader + disable depth/stencil test.

Depth Bias

When two primitives are rendered on top of each other or very close to it, their interpolated depth values may be the same or very close. Due to floating-point imprecision, this can result in depth testing producing inconsistent and implementation-dependent results. This visual artifact is known as depth fighting. Depth bias is used to alleviate this visual artifact by setting a programmable bias to force primitives to be offset toward or away from the viewer.

D3D12 has 3 parameters including DepthBias and DepthBiasClamp and SlopeScaledDepthBias to enable this feature.

Other features

Anti-alias: D3D12 has a few parameters like MultisampleEnable and AntialiasedLineEnable and ForcedSampleCount to cover anti-alias. We have a standalone investigation about MSAA by Jiawei. I will not cover anti-alias here.

Conservative Raster: The last parameter left in rasterizer descriptor in D3D12 is ConservativeRaster. It is not supported in Metal and Vulkan.

Metal

Unlike D3D12, Metal doesn't have a particular descriptor to cover these features. But it has some functions to configure them. Most functions are methods in MTLRenderCommandEncoder.

Triangle Fill Mode

Metal has a function MTLRenderCommandEncoder::setTriangleFillMode. This function can support two different triangle fill modes: line and fill, just like D3D12.

Front Face and Cull Mode

Front Face: Metal has a function MTLRenderCommandEncoder::setFrontFacingWinding. It can specify cw or ccw winding as triangle front face. And the other winding (ccw or cw) is thought to be back face. This feature is the same as the feature in D3D12.

Cull Mode: Metal has a function MTLRenderCommandEncoder::setCullMode to specify which facing will be culled and discarded. It can support none, front, and back, just like D3D12.

Depth Clip or Clamp

Metal has a function MTLRenderCommandEncoder::setDepthClipMode. It can support depth clip and depth clamp, just like D3D12.

Rasterization Discard

Metal can enable rasterization discard via isRasterizationEnabled in MTLRenderPipelineDescriptor.

Depth Bias

Metal can set all three parameters for depth bias via MTLRenderCommandEncoder::setDepthBias, just like D3D12.

Other features

Metal has a function named setVisibilityResultMode in MTLRenderCommandEncoder. It is used to control how to monitor samples that pass the depth and stencil tests. But it is not supported in D3D12 and Vulkan.

Vulkan

Vulkan has a standalone state to describe rasterization in its graphics pipeline: VkPipelineRasterizationStateCreateInfo. I'd like to list it here:

typedef struct VkPipelineRasterizationStateCreateInfo {
    VkStructureType                            sType;
    const void*                                pNext;
    VkPipelineRasterizationStateCreateFlags    flags;
    VkBool32                                   depthClampEnable;
    VkBool32                                   rasterizerDiscardEnable;
    VkPolygonMode                              polygonMode;
    VkCullModeFlags                            cullMode;
    VkFrontFace                                frontFace;
    VkBool32                                   depthBiasEnable;
    float                                      depthBiasConstantFactor;
    float                                      depthBiasClamp;
    float                                      depthBiasSlopeFactor;
    float                                      lineWidth;
} VkPipelineRasterizationStateCreateInfo;

Triangle Fill Mode

polygonMode in this state is used to describe triangle fill mode in Vulkan. its type is VkPolygonMode, which can support 4 different triangle fill modes: fill, line, and point. But Metal and D3D12 can only support fill and line.

(From Corentin's comments below) Triangle fill mode other than "fill" are an optional Vulkan feature gated by fillModeNonSolid that doesn't have wide support on mobile GPUs.

Front Face and Cull Mode

Front Face: Vulkan can specify triangle's front face via frontFace. Its type is VkFrontFace. This enumeration includes ccw and cw, just like Metal and D3D12.

Cull Mode: Vulkan can cull and discard some particular triangles if its facing falls to the facing specified by 'cullMode'. Its type is VkCullModeFlagBits, which includes none, front, back, and front and back. **But Metal and D3D12 can't support front and back.

Depth Clip or Clamp

Vulkan can enable depth clip or depth clamp via depthClampEnable. If it is false, then depth clip is enabled. Otherwise, depth clamp is enabled. This feature is the same as the feature in Metal and D3D12.

(From Corentin's comments below) Depth clamp is an optional Vulkan feature gated by depthClamp that's not widely supported on mobile chips.

Rasterization Discard

Vulkan can enable rasterization discard via rasterizationDiscardEnable, just like Metal.

Depth Bias

Vulkan can enable depth bias via 4 parameters: depthBiasEnable, depthBiasConstantFactor, depthBiasClamp, and depthBiasSlopeFactor. While Metal and D3D12 only have the latter 3 parameters. But if these parameters are 0 in Metal and D3D12, then depth bias is disabled.

Other features

Metal has a parameter lineWidth to support wide lines. But Metal and D3D12 don't have this feature. Furthermore, some Vulkan drivers only support wide lines via sw like drawing some triangles to emulate wide lines.

Conclusion and Proposal

Conclusion

Triangle Fill Mode

Metal, D3D12 can support 2 triangle fill modes: fill, and line. Vulkan may support one more fill mode point. But both line and point fill modes on Vulkan are optional. So we might not support this feature currently.

Front Face and Cull Mode

We can specify ccw or cw as front face in Metal, D3D12 and Vulkan. So we can support it in web idl.
Metal, D3D12 and Vulkan can support 3 cull modes: none, front, and back. So we can support these 3 cull modes in web idl. Vulkan can support one more cull mode front and back, though.

Depth Clip or Clamp

Metal and D3D12 can support depth clip/clamp. But depth clamp is an optional feature in Vulkan. However, dept clamp is useful for some scenarios. So we may support this feature as an extension.

Rasterization Discard

Metal and Vulkan can support rasterization discard directly. And it is doable in D3D12 because D3D12 can support stream output stage and enable rasterization discard (via an empty pixel shader + disable depth/stencil test).

(Updated from the comments below) But currently we can't guarantee that we can implement the technique like transform feedback or stream output in WebGPU (say via ssbo in vertex shader), so we might not to support rasterization discard in web idl right now.

Depth Bias

This feature can be supported in Metal, D3D12 and Vulkan in the same manner. However, this feature is hardware-dependent, I think we might not expose this feature to WebGPU. But I'd like to hear your thoughts about it.

(Updated from the comments below) Depth bias is used in some algorithms and requested by developers, so we will support it.

Proposal

Since many features related to rasterization can be supported by all 3 native APIs, I suggest we support them in WebGPU idl. In addition, both D3D12 and Vulkan have a standalone state/descriptor to group these features together, So I'd like to have a descriptor name WebGPURasterizationStateDescriptor and a state named WebGPURastierizationState as follow:

enum WebGPUTriangleFillMode {
    "fill",
    "line"
};

enum WebGPUFrontFace {
    "ccw",
    "cw"
};

enum WebGPUCullMode {
    "none",
    "front",
    "back"
};

enum WebGPUDepthClipMode {
    "clip",
    "clamp"
};

dictionary WebGPURasterizationStateDescriptor {
    WebGPUTriangleFillMode fillMode;
    WebGPUFrontFace frontFace;
    WebGPUCullMode cullMode;
    WebGPUDepthClipMode clipMode;
    bool rasterizationDiscardEnable;
};

interface WebGPURasterizationState {
};

In addition, we need to add an instance of WebGPURasterizationState into WebGPURenderPipelineDescriptor:

WebGPURasterizationState rasterizationState;

Finally, we need to add a function into WebGPUDevice:

WebGPURasterizationState createRasterizationState(WebGPURasterizationStateDescriptor descriptor); 

TODO

Update the WebGPU idl once we get consensus on this.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions