microsoft / microsoft/DirectXShaderCompiler
[Debug info] Mesh shader `vertices[]` / `primitives[]` / `indices[]`: missing or wrongly-offset debug info
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 3.7k
- Forks
- 900
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 44
Description
Version: dxcompiler.dll 1.9(5402-0d3ee6b5)(1.9.0.5402) - 1.9.0.5402 (0d3ee6b55-dirty)
Repro files: mesh_shader_repro.zip
Both repros share this signature:
struct Vertex { float4 position : SV_Position; float3 normal : NORMAL; };
struct Primitive { uint primID : SV_PrimitiveID; float shade : COLOR0; };
[numthreads(4, 1, 1)]
[outputtopology("triangle")]
void main(
uint gtid : SV_GroupThreadID,
out vertices Vertex verts[3],
out primitives Primitive prims[2],
out indices uint3 tris[2])
(a) Dynamic index: no debug info at all
dxc -T ms_6_5 -Zi -Qembed_debug -Od -Fc dynamic_index.ll dynamic_index.hlsl
if (gtid < 3)
{
verts[gtid].position = float4(t, t, t, 1.0);
verts[gtid].normal = float3(0, 0, 1);
}
if (gtid < 2)
{
prims[gtid].primID = gtid;
prims[gtid].shade = t;
tris[gtid] = uint3(0, 1, 2);
}
The only local variables in the whole module are gtid and t:
!DILocalVariable(tag: DW_TAG_arg_variable, name: "gtid", arg: 1, scope: !34, ...)
!DILocalVariable(tag: DW_TAG_auto_variable, name: "t", scope: !34, ...)
verts, prims and tris have no DILocalVariable and no dbg.value, despite
the dx.op.storeVertexOutput, dx.op.storePrimitiveOutput and
dx.op.emitIndices calls in the function.
(b) Constant index: fragment offsets use the wrong layout
dxc -T ms_6_5 -Zi -Qembed_debug -Od -Fc constant_index.ll constant_index.hlsl
Now all three arrays get a DILocalVariable, each typed as a plain
array-of-struct:
!92 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "verts", arg: 2, scope: !34, file: !1, line: 27, type: !39)
!104 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "prims", arg: 3, scope: !34, file: !1, line: 28, type: !47)
!109 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "tris", arg: 4, scope: !34, file: !1, line: 29, type: !55)
!39 = !DICompositeType(tag: DW_TAG_array_type, baseType: !40, size: 672, align: 32, elements: !44) ; Vertex[3]
!40 = !DICompositeType(tag: DW_TAG_structure_type, name: "Vertex", ..., size: 224, align: 32, elements: !41)
!42 = !DIDerivedType(tag: DW_TAG_member, name: "position", scope: !40, ..., size: 128, align: 32)
!43 = !DIDerivedType(tag: DW_TAG_member, name: "normal", scope: !40, ..., size: 96, align: 32, offset: 128)
!47 = !DICompositeType(tag: DW_TAG_array_type, baseType: !48, size: 128, align: 32, elements: !52) ; Primitive[2]
!48 = !DICompositeType(tag: DW_TAG_structure_type, name: "Primitive", ..., size: 64, align: 32, elements: !49)
!50 = !DIDerivedType(tag: DW_TAG_member, name: "primID", scope: !48, ..., size: 32, align: 32)
!51 = !DIDerivedType(tag: DW_TAG_member, name: "shade", scope: !48, ..., size: 32, align: 32, offset: 32)
!55 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 192, align: 32, elements: !52) ; uint3[2]
verts: wrong
verts[0].position = float4(t, t, t, 1.0);
verts[0].normal = float3(0, 0, 1);
verts[1].position = float4(1, 1, 1, 1);
verts[1].normal = float3(0, 1, 0);
var:"verts" !DIExpression(DW_OP_bit_piece, 0, 32) ; verts[0].position.x
var:"verts" !DIExpression(DW_OP_bit_piece, 32, 32) ; verts[0].position.y
var:"verts" !DIExpression(DW_OP_bit_piece, 64, 32) ; verts[0].position.z
var:"verts" !DIExpression(DW_OP_bit_piece, 96, 32) ; verts[0].position.w
var:"verts" !DIExpression(DW_OP_bit_piece, 384, 96) ; verts[0].normal
var:"verts" !DIExpression(DW_OP_bit_piece, 128, 128) ; verts[1].position
var:"verts" !DIExpression(DW_OP_bit_piece, 480, 96) ; verts[1].normal
| field | expected | emitted |
|---|---|---|
verts[0].position |
0, 128 | 0, 128 |
verts[0].normal |
128, 96 | 384, 96 |
verts[1].position |
224, 128 | 128, 128 |
verts[1].normal |
352, 96 | 480, 96 |
prims: wrong
The constant stores pin the mapping exactly:
call void @llvm.dbg.value(metadata i32 7, ...) ; var:"prims" !DIExpression(DW_OP_bit_piece, 0, 32)
call void @dx.op.storePrimitiveOutput.i32(i32 172, i32 0, i32 0, i8 0, i32 7, i32 0) ; prims[0].primID = 7
call void @llvm.dbg.value(metadata float 2.500000e-01, ...) ; var:"prims" !DIExpression(DW_OP_bit_piece, 64, 32)
call void @dx.op.storePrimitiveOutput.f32(i32 172, i32 1, i32 0, i8 0, float 2.500000e-01, i32 0) ; prims[0].shade = 0.25
call void @llvm.dbg.value(metadata i32 9, ...) ; var:"prims" !DIExpression(DW_OP_bit_piece, 32, 32)
call void @dx.op.storePrimitiveOutput.i32(i32 172, i32 0, i32 0, i8 0, i32 9, i32 1) ; prims[1].primID = 9
call void @llvm.dbg.value(metadata float 7.500000e-01, ...) ; var:"prims" !DIExpression(DW_OP_bit_piece, 96, 32)
call void @dx.op.storePrimitiveOutput.f32(i32 172, i32 1, i32 0, i8 0, float 7.500000e-01, i32 1) ; prims[1].shade = 0.75
| field | expected | emitted |
|---|---|---|
prims[0].primID |
0, 32 | 0, 32 |
prims[0].shade |
32, 32 | 64, 32 |
prims[1].primID |
64, 32 | 32, 32 |
prims[1].shade |
96, 32 | 96, 32 |
prims[0].shade and prims[1].primID are swapped: reading prims[0].shade
yields the bits of 9, and reading prims[1].primID yields the bits of 0.25.
tris: correct
var:"tris" !DIExpression(DW_OP_bit_piece, 0, 96) ; tris[0]
var:"tris" !DIExpression(DW_OP_bit_piece, 96, 96) ; tris[1]
Correct for uint3[2]. The index triple is a single signature row, so the
struct-of-arrays and array-of-struct layouts coincide and there is nothing to
transpose. tris is only affected by (a).
Root cause
The emitted offsets follow the struct-of-arrays layout of the lowered output
signature, one contiguous run per signature row indexed by element, while
the DILocalVariable's type is array-of-struct:
verts, 2 rows (position, normal): position[3] @ 0..383 normal[3] @ 384..671
prims, 2 rows (primID, shade): primID[2] @ 0..63 shade[2] @ 64..127
Expected
- Writes through a non-constant index should still describe the output array.
DW_OP_bit_pieceoffsets must be computed against the layout the
DILocalVariable's type describes.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with mesh_shader_repro.zip and run the two supplied dxc commands to inspect dynamic_index.ll and constant_index.ll. Trace the debug-info generation for mesh shader output arrays and compare emitted DW_OP_bit_piece offsets with the declared array-of-struct types. Done means dynamic indices have debug variables and constant-index offsets match those types.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100