generated from fastn-stack/fastn-template
-
Notifications
You must be signed in to change notification settings - Fork 1
/
wgsl.ftd
136 lines (99 loc) · 4.3 KB
/
wgsl.ftd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
-- my-ds.page: WGSL - Shader Languange for [WGPU](wgpu/)
WGSL is a Rust like language for writing shaders in WGPU. [Official
spec](https://gpuweb.github.io/gpuweb/wgsl/#attribute-location).
-- ds.code:
lang: wgsl
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) position: vec2<f32>,
};
@vertex
fn vs_main(
@builtin(vertex_index) in_vertex_index: u32,
) -> VertexOutput {
var out: VertexOutput;
let x = f32(1 - i32(in_vertex_index)) * 0.5;
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
out.position = vec2<f32>(x, y);
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
return out;
}
// Fragment shader
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(in.position, 0.5, 1.0);
}
-- ds.h1: What does `@builtin(position)` mean?
`builtin` is used twice, once as a `member of a structure` and once in `entry
point function parameter`.
Spec:
> Must only be applied to an entry point function parameter, entry point return
> type, or member of a structure.
The [builtin values are listed in the
spec](https://gpuweb.github.io/gpuweb/wgsl/#builtin-values). Each `Predeclared
Name`, eg `postion` and `vertex_index` in this example, have an associated
`stage`, listed in the spec. `stage` is either `vertex` for vertex shaders,
`frgament` or `compute`. Spec also tells us value is an input or output.
`@builtin(position)` for example is `input` for `fragment shaders`, but
`output` for `vertex shader`.
-- ds.h1: What is `@location(0)`
In the struct definition we see location ([spec
link](https://gpuweb.github.io/gpuweb/wgsl/#attribute-location)).
The index, eg `0`:
> Must be a const-expression that resolves to an i32 or u32. Must be
> non-negative.
- Can not be used with `compute shaders`.
- Each input-output location can store a value up to 16 bytes in size.
From the spec: [10.3.1.3. Input-output
Locations](https://gpuweb.github.io/gpuweb/wgsl/#input-output-locations):
> Each user-defined input and output must have an explicitly specified IO
location. Each **structure member in the entry point IO must be one of either
a built-in value** (see §10.3.1.1 Built-in Inputs and Outputs), or assigned a
location.
And
> Location numbering is distinct between inputs and outputs: Location numbers
for an entry point’s shader stage inputs do not conflict with location
numbers for the entry point’s shader stage outputs.
Basically every input or output is just an array of `data up to 16 bytes in
size`. The struct and argument orders are for programmers convenience, and the
location number is how things are laid out in memory.
Could be `@location()` is for input user can send, and `@builtin()` stuff are
for data that shaders get from GPU directly.
-- ds.h1: What is `clip_position`?
A simpler triangle drawing shader is:
-- ds.code:
lang: wgsl
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
};
@vertex
fn vs_main(
@builtin(vertex_index) in_vertex_index: u32,
) -> VertexOutput {
var out: VertexOutput;
let x = f32(1 - i32(in_vertex_index)) * 0.5;
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
return out;
}
// Fragment shader
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(0.3, 0.2, 0.1, 1.0);
}
-- ds.markdown:
As you see the `clip_position` is not used in the `fragment` shader. In the
earlier example we had two output fields, `clip_position` and `position`.
The `position` was used to create a location in memory where the output of the
vertex shader would be stored. And in the corresponding fragment shader that
`in.position` was used. So `@location()` stuff is for creating locations in
memory for shaders to talk to each other.
Who uses `clip_position`? So the vertex shader is calculating it and storing
in a GPU aware location called `clip_position`. What is interesting to me is
who is consuming the output of the fragment shader? I would have thought GPU
consumes it so the output should be stored in some `@builtin` location, why
is it using the output of fragment shaders in a "user-defined" location? One
can argue the output of fragment shader is consumed by GPU only, so it makes
no difference and `@location(0)` is an alias for say `@builtin(color)` or
something.
-- end: my-ds.page