This adds support for #pragma pack_matrix() to the HLSL front end.
The pragma sets the default matrix layout for subsequent unqualified matrices
in structs or buffers. Explicit qualification overrides the pragma value. Matrix
layout is not permitted at the structure level in HLSL, so only leaves which are
matrix types can be so qualified.
Note that due to the semantic (not layout) difference in first matrix indirections
between HLSL and SPIR-V, the sense of row and column major are flipped. That's
independent of this PR: just a factor to note. A column_major qualifier appears
as a RowMajor member decoration in SPIR-V modules, and vice versa.
The HLSL FE tracks four versions of a declared type to avoid losing information, since it
is not (at type-decl time) known how the type will be used downstream. If such a type
was used in a cbuffer declaration, the cbuffer type's members should have been using
the uniform form of the original user structure type, but were not.
This would manifest as matrix qualifiers (and other things, such as pack offsets) on user struct
members going missing in the SPIR-V module if the struct type was a member of a cbuffer, like so:
struct MyBuffer
{
row_major float4x4 mat1;
column_major float4x4 mat2;
};
cbuffer Example
{
MyBuffer g_MyBuffer;
};
Fixes: #789
This allows removal of isPerVertexBuiltIn(). It also leads to
removal of addInterstageIoToLinkage(), which is no longer needed.
Includes related name improvements.
The goal is to flatten all I/O, but there are multiple categories and
steps to complete, likely including a final unification of splitting
and flattening.
Most of this was obsoleted by entry-point wrapping.
Some other is just unnecessary.
Also, includes some spelling/name improvements.
This is to help lay ground work for flattening user I/O.
Two non-functional changes:
1. Remove flattenLevel, which is unneeded since at or around d1be7545c6.
2. Fix build warining about unused variable in executeInitializer.
HLSL allows several variables to be declared. There are packing rules involved:
e.g, a float3 and a float1 can be packed into a single array[4], while for a
float3 and another float3, the second one will skip the third array entry to
avoid straddling
This is implements that ability. Because there can be multiple variables involved,
and the final output array will often be a different type altogether (to fuse
the values into a single destination), a new variable is synthesized, unlike the prior
clip/cull support which used the declared variable. The new variable name is
taken from one of the declared ones, so the old tests are unchanged.
Several new tests are added to test various packing scenarios.
Only two semantic IDs are supported: 0, and 1, per HLSL rules. This is
encapsulated in
static const int maxClipCullRegs = 2;
and the algorithm (probably :) ) generalizes to larger values, although there
are a few issues around how HLSL would pack (e.g, would 4 scalars be packed into
a single HLSL float4 out reg? Probably, and this algorithm assumes so).
--resource-set-binding has a mode which allows per-register assignments of
bindings and descriptor sets on the command line, and another accepting a
single descriptor set value to assign to all variables.
The former worked, but the latter would crash when assigning the values.
This fixes it, and makes the former case a bit more robust against premature
termination of the pre-register values, which must come in (regname,set,binding)
triples.
This also allows the form "--resource-set-binding stage setnum", which was
mentioned in the usage message, but did not parse.
The operation of the per-register form of this option is unchanged.
From comment about this:
Adjust alignment for HLSL rules
TODO: make this consistent in early phases of code: adjusting this late means inconsistencies with earlier code, which for reflection is an issue.
Until reflection is brought in sync with these adjustments, don't apply to $Global,
which is the most likely to rely on reflection, and least likely to rely
implicit layouts.
Semantic test left over from other source languages is removed, since this is permitted by HLSL.
Also, to support the functionality, a targeted test is performed for this case and it is
turned into a EvqGlobal qualifier to create an AST initialization segment when needed.
Constness is now propagated up aggregate chains during initializer construction. This
handles hierarchical cases such as the distinction between:
static const float2 a[2] = { { 1, 2 }, { 3, 4} };
vs
static const float2 a[2] = { { 1, 2 }, { cbuffer_member, 4} };
The first of which can use a first class constant initalization, and the second cannot.