-
Notifications
You must be signed in to change notification settings - Fork 353
Description
Proposal
Each location represents 16-bytes of storage. The size of elements are determined using the SizeOf column in default memory layout. For example, a four-element vector of floating-point values consumes a single location. Locations are consumed consecutively from the specified initial location until the size of the element is completely contained. Neither structure members nor different array elements can share a location. There are no default locations. That is, all user-defined entry point return value and function parameters must be assigned a location according to the following rules.
Example: applying the location attribute
struct A {
[[location(0)]] x : vec4<f32>;
[[location(1)]] y : u32;
// Despite locations being 16-bytes, z cannot share location 1 with y.
[[location(2)]] z : f32;
};
struct B {
x : vec4<f32>;
y : u32;
};
// in1 consumes input locations 0, 1 and 2.
// in2 consumes input locations 3 and 4.
// The return value consumes output locations 0 and 1.
[[stage(fragment)]] shader(in1 : A, [[location(3)]] in2 : B) -> [[location(0)]] B {
// …
}
The location attribute must be specified for user-defined entry point parameter and return value declarations. That is, values that do not have the builtin attribute specified. The location attribute can either be specified directly on the parameter declaration or return value, or if the parameter or return values are struct types, on the members of those structs. If a location attribute is specified directly on the parameter or return value declarations then it must not contain a builtin declaration. Builtins and user-defined I/O can be mixed, but the attributes must be applied at the same level. If location attributes are applied to members of a structure, those locations must be monotonically increasing.
Example: mixing builtin and user-defined I/O.
// Struct that consumes 4 locations.
struct SubData {
a : array<vec4<f32>, 4>;
};
// Mixed builtins and user-defined inputs
struct MyInputs {
// Consumes location 0.
[[location(0)]] x : vec4<f32>;
[[builtin(front_facing)]] y : bool;
// Consumes locations 1 through 4.
[[location(1)]] z : SubData;
// Consumes location 5.
[[location(5)]] w : u32;
};
// Mixed builtins and user-defined outputs.
struct MyOutputs {
[[builtin(frag_depth)]] depth : f32;
// Consumes locations 0 through 3.
[[location(0)]] x : SubData;
};
[[stage(fragment)]] shader(in1 : MyInputs) -> MyOutputs {
// …
}
For a given entry point, the locations of the return value are distinct from the locations of the function parameters Within each set of locations, there must be no overlap.
Note: the number of available locations is defined by the API.
Example: invalid location assignments.
struct A {
x : vec4<f32>;
y : vec4<f32>;
};
struct B {
[[location(0)]] a1 : A;
// a1 consumes locations 0 and 1 so assigning location 1 to a2 is invalid.
[[location(1)]] a2 : A;
};
struct C {
[[location(0)]] x : f32;
// y cannot be packed into the same location as x.
[[location(0)]] y : u32;
};
Mappings
HLSL
HLSL allows mixing builtins and user-defined I/O in structs. Therefore, the main concern is mapping the location attribute. For vertex shaders and fragment shader inputs, location should map to the semantic TEXCOORDN, where N is the location number of the attribute. For fragment shader outputs, location should map to SV_TargetN (COLORN before Shader Model 6.0), where N is the location number for the attribute.
Note: function returns in WGSL need to be converted to parameters in the HLSL shader.
MSL
MSL allows mixing builtins and user-defined I/O in structs. In order to simplify interface matching, location attributes should be translated to user attributes (e.g. [[user(locN)]], where N is the location number).
Note: all inputs should be gathered into a single parameter with the stage_in attribute.
SPIR-V
Location attributes map directly to SPIR-V; however, structs should not contain both builtins and user-defined I/O. Additionally any struct should be block-decorated.
Note: struct returns and parameters could be scalarized completely in the SPIR-V backend as long as the location attributes are propagated.