KhronosGroup / KhronosGroup/glslang
HLSL: the counter created for for AppendStructuredBuffer use the same set and binding as the original buffer
- Dominant language
- C++
- Stars
- 3.6k
- Forks
- 989
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 31
Description
When Glslang creates a counter for an AppendStructuredBuffer, the additional buffer is placed in the same (set,binding) slot as its associated buffer. I think that's a bug because it's a binding collision. DXC puts the associated counter in the binding right after the associated buffer. Examples below.
(Neither variable gets an Index decoration)
Consider this shader with an AppendStructuredBuffer:
```
AppendStructuredBuffer outputs;
[numthreads(1,1,1)]
void main() {
outputs.Append(1.0);
}
```
Let's say I put it in file `x.comp`
I compile it to SPIR-V, using : `glslang -D -e main -V100 --hlsl-iomap x.comp -o x.spv`
I get this SPIR-V:
```
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 11
; Bound: 32
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 500
OpName %main "main"
OpName %outputs "outputs"
OpMemberName %outputs 0 "@data"
OpName %outputs_0 "outputs"
OpName %outputs_count "outputs@count"
OpMemberName %outputs_count 0 "@count"
OpName %outputs_count_0 "outputs@count"
OpDecorate %_runtimearr_float ArrayStride 4
OpMemberDecorate %outputs 0 Offset 0
OpDecorate %outputs BufferBlock
OpDecorate %outputs_0 DescriptorSet 0
OpDecorate %outputs_0 Binding 0
OpMemberDecorate %outputs_count 0 Offset 0
OpDecorate %outputs_count BufferBlock
OpDecorate %outputs_count_0 DescriptorSet 0
OpDecorate %outputs_count_0 Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%_runtimearr_float = OpTypeRuntimeArray %float
%outputs = OpTypeStruct %_runtimearr_float
%_ptr_Uniform_outputs = OpTypePointer Uniform %outputs
%outputs_0 = OpVariable %_ptr_Uniform_outputs Uniform
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%uint = OpTypeInt 32 0
%outputs_count = OpTypeStruct %uint
%_ptr_Uniform_outputs_count = OpTypePointer Uniform %outputs_count
%outputs_count_0 = OpVariable %_ptr_Uniform_outputs_count Uniform
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
%uint_1 = OpConstant %uint 1
%uint_0 = OpConstant %uint 0
%float_1 = OpConstant %float 1
%_ptr_Uniform_float = OpTypePointer Uniform %float
%main = OpFunction %void None %3
%5 = OpLabel
%29 = OpAccessChain %_ptr_Uniform_uint %outputs_count_0 %int_0
%30 = OpAtomicIAdd %uint %29 %uint_1 %uint_0 %uint_1
%31 = OpAccessChain %_ptr_Uniform_float %outputs_0 %int_0 %30
OpStore %31 %float_1
OpReturn
OpFunctionEnd
```
Note that variable `%outputs_0` and its associated counter `%outputs_count_0` both get descriptor set 0 and binding 0.
I think this is a bug because they collide.
DXC's SPIR-V output puts the counter in binding 1.
Compile with `dxc -spirv -T cs_6_0 -E main x.comp -Fo x.d.spv -fspv-reflect`
I get the following. Note that `%counter_var_outputs` is in set 0, binding 1.
```
; SPIR-V
; Version: 1.0
; Generator: Google spiregg; 0
; Bound: 24
; Schema: 0
OpCapability Shader
OpExtension "SPV_GOOGLE_hlsl_functionality1"
OpExtension "SPV_GOOGLE_user_type"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 600
OpName %type_AppendStructuredBuffer_float "type.AppendStructuredBuffer.float"
OpName %outputs "outputs"
OpName %type_ACSBuffer_counter "type.ACSBuffer.counter"
OpMemberName %type_ACSBuffer_counter 0 "counter"
OpName %counter_var_outputs "counter.var.outputs"
OpName %main "main"
OpDecorateId %outputs CounterBuffer %counter_var_outputs
OpDecorate %outputs DescriptorSet 0
OpDecorate %outputs Binding 0
OpDecorate %counter_var_outputs DescriptorSet 0
OpDecorate %counter_var_outputs Binding 1
OpDecorate %_runtimearr_float ArrayStride 4
OpMemberDecorate %type_AppendStructuredBuffer_float 0 Offset 0
OpDecorate %type_AppendStructuredBuffer_float BufferBlock
OpDecorateString %outputs UserTypeGOOGLE "appendstructuredbuffer:"
OpMemberDecorate %type_ACSBuffer_counter 0 Offset 0
OpDecorate %type_ACSBuffer_counter BufferBlock
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%float = OpTypeFloat 32
%float_1 = OpConstant %float 1
%_runtimearr_float = OpTypeRuntimeArray %float
%type_AppendStructuredBuffer_float = OpTypeStruct %_runtimearr_float
%_ptr_Uniform_type_AppendStructuredBuffer_float = OpTypePointer Uniform %type_AppendStructuredBuffer_float
%type_ACSBuffer_counter = OpTypeStruct %int
%_ptr_Uniform_type_ACSBuffer_counter = OpTypePointer Uniform %type_ACSBuffer_counter
%void = OpTypeVoid
%16 = OpTypeFunction %void
%_ptr_Uniform_int = OpTypePointer Uniform %int
%uint_1 = OpConstant %uint 1
%_ptr_Uniform_float = OpTypePointer Uniform %float
%outputs = OpVariable %_ptr_Uniform_type_AppendStructuredBuffer_float Uniform
%counter_var_outputs = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform
%main = OpFunction %void None %16
%20 = OpLabel
%21 = OpAccessChain %_ptr_Uniform_int %counter_var_outputs %uint_0
%22 = OpAtomicIAdd %int %21 %uint_1 %uint_0 %int_1
%23 = OpAccessChain %_ptr_Uniform_float %outputs %uint_0 %22
OpStore %23 %float_1
OpReturn
OpFunctionEnd
```
Contributor guide
Research direction
Reproduce the collision with the issue's x.comp shader and the shown glslang command, then compare its SPIR-V descriptor assignments with the DXC output. Trace the HLSL resource and counter binding generation in glslang; done means the counter receives a distinct binding after the associated buffer without collisions.
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
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100