-
Notifications
You must be signed in to change notification settings - Fork 329
Description
#2321 adds an orthogonal type system for uniformity in addition to the regular type system that describes the shape of manipulated values. That type system is completely implicit and done as a whole-program analysis. This makes it somewhat hard for developers to reason about it because changes on a leaf function could cause type violation in functions higher in the callgraph.
The analysis provides some way to produce good errors messages but they will be at the function level (unless we keep the whole uniformity implication graph in memory) and could be really long as they don't stop at function boundary. It is also hard for developers to know at a glance what uniformity guarantees a function requires.
That's why I suggest that we have optional type annotations in WGSL that declare that a given variable must be uniform, or a function must be called in uniform control flow. This way developers can annotate the expectations of their code, which will be checked by the compiler. I'm not attached to the particular syntax but here's an example of what it could look like:
@uniform fn myFunction() {}
if (nonUniformBool) {
// Compilation error: "myFunction is called in non-uniform control flow".
myFunction();
}
fn myFunction(b: @uniform bool) {}
// Compilation error: "myFunction parameter is called with a non-uniform `b`"
myFunction(nonUniformBool);
In addition to letting developers spell out the contract of their functions better, it allows them to write compile time assertions of their understanding of uniformity:
@uniform fn assertUniformControlFlow() {}
fn assertUniformU32(v: @uniform u32) {}
It also allows specifying the uniformity constraints of builtins independently of the uniformity analysis. Some examples:
@uniform dpdx(e:T) -> T
@uniform textureSample(t: @uniform texture_2d<f32>, s: sampler, coords: vec2<f32>) -> vec4<f32>
@uniform workgroupBarrier()
workgroup_id : @uniform u32
Finally I think we should differentiate between various kinds of uniformity:
- Completely uniform values for a draw / dispatch: things that depend only on constants / uniform buffer values.
- Workgroup uniform values.
- Subgroup uniform values (when we have that extension)
- Quad uniform values (without quad ops it's the same as completely uniform for a draw, but would come with an extension)
- Maybe (but I'm not sure at all) compile-time / override-uniform. This means we can express that the
offset
oftextureSample
must be a constexpr.
This could be done by having the attribute @uniform
default to a different uniformity value depending on the shader stage (VS: full uniform, FS: quad uniform, CS: workgroup uniform), then also have a way for users to specify the exact uniformity. uniform(complete/workgroup/subgroup/quad/none)
.