-
Notifications
You must be signed in to change notification settings - Fork 336
Description
This document attempts to describe the differences between pipeline states in the current generation of graphics APIs. It also touches some adjacent features like stencil reference values and blend factors. The investigation uses materials from https://github.com/jdashg/vulkan-portability/blob/master/pipeline-state.md.
Information
The concept of a pipeline state is similar between Vulkan/D3D12/Metal. A graphics PSO (short for Pipeline State Object) is an opaque object encapsulating the following information:
- shaders for active stages
- primitive topology, vertex input layout, tessellation
- rasterizer, blend, depth/stencil states, multi-sampling
- render targets descriptions
Graphics and compute pipelines are represented with separate types and constructed from different states. We'll focus on the graphics one, considering the compute to use a subset of graphics states.
Differences between APIs are mostly laid out within the specification of render targets and the range of supported states within particular stages.
Vulkan
vkCreateGraphicsPipelineStates
creates multiple pipeline states at once, each from a separate VkGraphicsPipelineCreateInfo struct. Users can provide a pipeline cache object in order to re-use internal parts (opaque to the user) between pipelines.
Instead of specifying the formats of render targets, the pipeline state is created for a specific sub-pass of a render pass. A pipeline can then be used with any compatible render pass, according to the rules.
Vulkan allows certain states to be either baked into PSO or set independently during command encoding:
typedef enum VkDynamicState {
VK_DYNAMIC_STATE_VIEWPORT = 0,
VK_DYNAMIC_STATE_SCISSOR = 1,
VK_DYNAMIC_STATE_LINE_WIDTH = 2,
VK_DYNAMIC_STATE_DEPTH_BIAS = 3,
VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4,
VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5,
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6,
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7,
VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8,
} VkDynamicState;
Vulkan multi-sampling state allows not only forcing sample shading on/off but also specifying the ratio of uniquely shaded samples. This is gated by sampleRateShading
feature of the device. Similarly, independent blending is supported behind the independentBlend
feature.
VkVertexInputRate
does not seem to support instance rate values higher than 1, although it seems trivial to extend the range of accepted values for this type.
Direct3D 12
CreateGraphicsPipelineState
creates a graphics PSO described by the D3D12_GRAPHICS_PIPELINE_STATE_DESC structure.
Color and depth render targets are described by their format.
The user can pass a cache blob of another PSO in order to re-use the internal compiled parts.
For multi-sampling, D3D12 exposes the DXGI_SAMPLE_DESC::Quality
value, the semantics of which is rather opaque but the exposed capabilities are similar to Vulkan's minSampleShading
. Comparing to Vulkan, various parts of multi-sampling state are spread over the rasterization state, blending, sample descriptors, and plain values in the PSO descriptor.
Limitations compared to Vulkan:
- no
VK_CULL_MODE_FRONT_AND_BACK
- no
VK_POLYGON_MODE_POINT
- no
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN
- only integer constant depth bias
- no separate stencil read/write masks and reference value
- no configurable sample shading
- 32bit sample mask
Extra features compared to Vulkan:
InstanceDataStepRate
allows an advance of vertex attribute per N instances- conservative rasterization
Metal
A graphics PSO is created via makeRenderPipelineState
from MTLRenderPipelineDescriptor.
There is no notion of pipeline cache as well as pipeline layout (aka root signature).
States that are surprisingly out of PSO:
- depth bias
- cull mode
- triangle fill mode
- depth/stencil
Limitations compared to Vulkan:
- no
VK_CULL_MODE_FRONT_AND_BACK
- no
VK_POLYGON_MODE_POINT
- no
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN
- no variable shading
- no sample mask (interesting, why?)
- no depth bounds
Extra features compared to Vulkan:
MTLVertexBufferLayoutDescriptor::stepRate
allows to configure the rate of an instanced attribute
Analysis
In both Vulkan and D3D12 there is a separate object describing resource binding layout and push/root constants, called VkPipelineLayout
and ID3D12RootSignature
correspondingly. It makes sense to have it in GPUWeb as well (related to #19).
Vulkan dynamic states are useful in order to match the PSO-baked states with D3D12 and Metal. Thus, we consider all of the dynamic states to be used at all times by the Vulkan backend of GPUWeb.
In terms of pipeline states, it seems reasonable to use the intersection of capabilities between the APIs, which happens to match D3D12 except for:
- instance rate, which we can limit to 1 for the MVP and revise later
- sample mask
I find it rather unfortunate if we had to drop support for the sample mask, thus perhaps we could patch the shader code in order to apply the mask in the shader specifically for Metal and support it uniformly.
The question of whether render target formats are needed in the PSO depends on #23. If render sub-passes are accepted, I believe following Vulkan model (of providing the pass and sub-pass index) is straightforward.
TODO:
- tessellation
- format of vertex data and color/depth/stencil targets