vkd3d-shader/dxil: Also map dst writemasks for sysvals.

Currently, on what we consider normalized vsir, dst writemasks are not relative to the signature element's mask, even though src swizzles are. Also for most instructions, the src swizzles are masked by the dst writemask, as given by vsir_src_is_masked().

The DXIL parser however, is not derelativizing the dst writemasks for sysval signature elements, so we fix that to make it consistent with how other frontends are handled.

For instance, when the test introduced in 1/2 is compiled to DXIL using DXC, and then parsed using vkd3d-compiler, we get the following store instructions:

vs_6_0
.input
.param POSITION.xyzw, v0.xyzw, float
.output
.param SV_Position.xyzw, o0.xyzw, float, POS
.param SV_CullDistance.x, o1.x, float, CULLDST
.param SV_ClipDistance.y, o1.y, float, CLIPDST
.descriptors
.text
label l1
    ...
    mov o1.x <v4:f32>, sr1 <s:f32>
    mov o2.x <v4:f32>, sr2 <s:f32> // NOTE the .x writemask!
    ret

whereas, when compiling using FXC and parsing the TPF using vkd3d-compiler we get:

vs_4_0
.input
.param POSITION.xyzw, v0.xyzw, float
.output
.param SV_POSITION.xyzw, o0.xyzw, float, POS
.param SV_CULLDISTANCE.x, o1.x, float, CULLDST
.param SV_CLIPDISTANCE.y, o1.y, float, CLIPDST
.descriptors
.text
label l1
    mov o0.xyzw <v4:f32>, v0.xyzw <v4:f32>
    mov o1.x <v4:f32>, v0.x <v4:f32>
    mov o2.y <v4:f32>, v0.y <v4:f32> // NOTE the .y writemask.
    ret

This only really matters for cases where we have a sysval semantic whose mask doesn't start at .x, which is very rare. For instance, it requires the clip/cull distance combo, which share registers, so one of them pushes the other to start on another component.

According to the tests, the only thing relying on this behavior is the handling of private variables for sysval semantics on the SPIR-V backend, which expects dst writemasks as if the element started at .x even though it might not. This is modified then.

Merge request reports

Loading