The handling of system-value semantics is going to get messy if we can't systematize it, and unfortunately this is also one part of the compiler where we can expect a reasonable amount of churn when supporting new targets, extensions, etc.
In an ideal world we should be able to define a system-value semantic in the standard library using code like:
[profile(vertex)]
out __systemValue SV_Position : float4;
Here the name of the system value is SV_Position, and it is registered as an out semantic for the vertex profile/stage, with type float4.
Semantics like this would need to occupy their own namespace, distinct from ordinary identifiers, so we might actually register this in the symbol tables with a name like semantic$sv_position (note that we case-fold the semantic name because semantics are case-insensitive).
During the front-end checking of an entry-point function, we should scan its input/output varying signature, and discover any system-value semantics used. This requires a table of known "system-value semantic prefixes", which could either be constructed by the stdlib, or be built into the compiler (with support for extending via API).
For a semantic that matches a known system-value semantic prefix, we'd look for a matching system-value semantic by name. We'd then apply a process similar to function overload resolution to refine a list of "candidate" semantic declarations down to the one we actually can use. If at any step we find that we run out of candidates, we would issue an error message. Error conditions we should diagnose separately include:
No system-value semantic exists with the given name
The system value is specific to a different profile/stage than the one chosen for the entry point
The system value is being used as an out, but is specified as in (or vice versa)
The system value expects type X, but is declared with type Y
One gotcha here is that some system-value semantics may support a variety of different declaration types (e.g., you can write out a float3 for SV_Position). We could either exhaustively enumerate the available cases, or else we could introduce support for generic __systemValue declarations if we really need that degree of flexibility (I'd rather not...).
A few more details to keep track of:
There are system values that support multiple values with the same semantic, but different indices. We'd probably need a way to indicate these, and also give a limit on the available index range.
We need a plan for how to deal with conversion of system values to the equivalent GLSL built-in variables. This includes cases where those variables might have a different type than the HLSL version.
In a completely ideal world, it would be great to be able to treat a system value as if it were a function declaration, so that a read of the given system value turns into a call of the chosen function (a function that returns the value in the in case, or that consumes the value in the out case). That might be feasible in the GLSL output case, but it would take more work to figure out what is needed in the SPIR-V or DXIL output case.
For now, by-hand translation of the system values we care about is probably okay.
The handling of system-value semantics is going to get messy if we can't systematize it, and unfortunately this is also one part of the compiler where we can expect a reasonable amount of churn when supporting new targets, extensions, etc.
In an ideal world we should be able to define a system-value semantic in the standard library using code like:
Here the name of the system value is
SV_Position
, and it is registered as anout
semantic for thevertex
profile/stage, with typefloat4
.Semantics like this would need to occupy their own namespace, distinct from ordinary identifiers, so we might actually register this in the symbol tables with a name like
semantic$sv_position
(note that we case-fold the semantic name because semantics are case-insensitive).During the front-end checking of an entry-point function, we should scan its input/output varying signature, and discover any system-value semantics used. This requires a table of known "system-value semantic prefixes", which could either be constructed by the stdlib, or be built into the compiler (with support for extending via API).
For a semantic that matches a known system-value semantic prefix, we'd look for a matching system-value semantic by name. We'd then apply a process similar to function overload resolution to refine a list of "candidate" semantic declarations down to the one we actually can use. If at any step we find that we run out of candidates, we would issue an error message. Error conditions we should diagnose separately include:
out
, but is specified asin
(or vice versa)One gotcha here is that some system-value semantics may support a variety of different declaration types (e.g., you can write out a
float3
forSV_Position
). We could either exhaustively enumerate the available cases, or else we could introduce support for generic__systemValue
declarations if we really need that degree of flexibility (I'd rather not...).A few more details to keep track of:
There are system values that support multiple values with the same semantic, but different indices. We'd probably need a way to indicate these, and also give a limit on the available index range.
We need a plan for how to deal with conversion of system values to the equivalent GLSL built-in variables. This includes cases where those variables might have a different type than the HLSL version.
In a completely ideal world, it would be great to be able to treat a system value as if it were a function declaration, so that a read of the given system value turns into a call of the chosen function (a function that returns the value in the
in
case, or that consumes the value in theout
case). That might be feasible in the GLSL output case, but it would take more work to figure out what is needed in the SPIR-V or DXIL output case.For now, by-hand translation of the system values we care about is probably okay.