8000 Added an explainer for primitive-index feature (#5293) · gpuweb/gpuweb@c79f865 · GitHub
[go: up one dir, main page]

Skip to content

Commit c79f865

Browse files
authored
Added an explainer for primitive-index feature (#5293)
To help the intent-to-ship process along. A modification/cleanup of Dan's original doc in the Dawn repo.
1 parent 1a35936 commit c79f865

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

proposals/primitive-index.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Primitive Index
2+
3+
The WebGPU feature `primitive-index` introduces the ability to use the `primitive_index` builtin in fragment shaders in WGSL.
4+
5+
## Motivation
6+
7+
The `primitive_index` is a unique integer for each primitive (triangle, line, or point) in a single drawn instance. This is useful in a variety of effects, from simple uses like computing flat shading to more complex uses such as advanced material effects or supporting modern virtualized geometry pipelines.
8+
9+
It is a common feature in the underlying native APIs (D3D, Metal, Vulkan, OpenGL), and as a result supporting this builtin increases the number of shaders that can be directly ported to the web.
10+
11+
## Status
12+
This feature has been approved by the working group and added to the WebGPU and WGSL specs.
13+
14+
## Native API Availability
15+
| Platform | Type | Notes |
16+
|----------|------|-------|
17+
| SPIR-V | 32-bit integer | Requires geometry shaders, mesh shaders, or raytracing. Available as the `PrimitiveID` builtin |
18+
| HLSL | u32 | Requires D3D10. Available as the `SV_PrimitiveID` semantic |
19+
| GLSL | i32 | Requires GLSL 1.50 and later, ESSL 3.2. (ESSL 3.1 with GL_EXT_geometry_shader). Available as the `gl_primitiveID` builtin |
20+
| Metal | u32 | Requires Metal 2.2 on MacOS or Metal 2.3 on iOS. Available as `[[primitive_id]]` |
21+
22+
Due to non-universal availability, use of this builtin will be gated behind a WebGPU feature, `primitive-index`. Also, the `enable primitive_index` statement will be required when using this builtin with WGSL.
23+
24+
## Behavior
25+
* `primitive_index` is restricted to `fragment` shaders.
26+
* The index of the first primitive is zero, incrementing by one for each subsequent primitive.
27+
* The `primitive_index` resets to zero between each instance drawn.
28+
* The `primitive_index` value is uniform across the primitive.
29+
* Primitive restart has no effect on the value of variables decorated with `primitive_index`.
30+
* HLSL specifies that if the primitive id overflows (exceeds 2^32 – 1), it wraps to 0.
31+
* This should not apply to WebGPU since all applicable draw call count arguments are unsigned 32 bit integers, and thus can never exceed that.
32+
* There is no support for automatically generating a primitive index for adjacent primitives.
33+
* For an adjacent primitive, the index is only maintained for the internal non-adjacent primitives.
34+
35+
All of the topologies in `GPUPrimitiveTopology` are supported. (Generally, adjacency topologies would
36+
not be supported but WebGPU does not have any adjacency topologies).
37+
38+
| Topology | Primitive |
39+
|----------|-----------|
40+
| point-list | Each vertex is a primitive |
41+
| line-list | Each vertex pair is a primitive |
42+
| line-strip | Each adjacent vertex pair is a primitive |
43+
| triangle-list | Each vertex triplet is a primitive |
44+
| triangle-strip | Each group of 3 adjacent vertices is a primitive |
45+
46+
## WGSL Specification
47+
This extension adds a new `builtin_value_name` entry for `primitive_index`.
48+
An entry is added to the _Built-in input and output values_ table:
49+
* _Name_: `primitive_index`
50+
* _Stage_: `fragment`
51+
* _Direction_: `input`
52+
* _Type_: `u32`
53+
* _Extension_: `primitive_index`
54+
55+
## Example usage
56+
57+
Enabling the `primitive-index` feature for a `GPUDevice`:
58+
59+
```js
60+
const adapter = await navigator.gpu.requestAdapter();
61+
62+
const requestedFeatures = [];
63+
if (adapter.features.has('primitive-index')) {
64+
requestedFeatures.psuh('primitive-index');
65+
} else {
66+
// Use an alternate code path or communicate error to user.
67+
}
68+
69+
const device = await adapter.requestDevice({ requestedFeatures });
70+
```
71+
72+
Using `primitive_index` builtin in a WGSL shader:
73+
74+
```wgsl
75+
enable primitive_index
76+
77+
@fragment fn fs_main(@builtin(primitive_index) prim_index: u32) -> @location(0) vec4f {
78+
return vec4f(f32(prim_index));
79+
}
80+
```
81+
82+
## Alternatives considered
83+
84+
The value that the `primitive_index` provides is impossible to emulate in all situations without API support. The most practical route would be to calculate the index from the existing `vertex_index` builtin, but this does not support indexed geometry. Given that indexed geometry is the most common format for large meshes and can reduce memory requirements significantly, this is not a viable restriction.
85+
86+
## References
87+
* [GLSL gl_PrimitiveID](https://registry.khronos.org/OpenGL-Refpages/gl4/html/gl_PrimitiveID.xhtml)
88+
* [GL_EXT_geometry_shader](https://registry.khronos.org/OpenGL/extensions/EXT/EXT_geometry_shader.txt)
89+
* [ESSL gl_PrimitiveID](https://registry.khronos.org/OpenGL-Refpages/es3/html/gl_PrimitiveID.xhtml)
90+
* [HLSL PrimitiveId](https://learn.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-input-assembler-stage-using#primitiveid)
91+
* [HLSL SV_PrimitiveId](https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics)
92+
* [HLSL FunctionalSpec](https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#:~:text=declaration%20for%20Shaders.-,8.17%20PrimitiveID,-PrimitiveID%20is%20a)
93+
* [Metal p.119](https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf)
94+
* [Vulkan PrimitiveId](https://registry.khronos.org/vulkan/specs/latest/man/html/PrimitiveId.html)

0 commit comments

Comments
 (0)
0