KhronosGroup / glslang

Khronos-reference front end for GLSL/ESSL, partial front end for HLSL, and a SPIR-V generator.
Other
2.9k stars 815 forks source link

HLSL: the counter created for for AppendStructuredBuffer use the same set and binding as the original buffer #3638

Open dneto0 opened 3 days ago

dneto0 commented 3 days ago

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<float> 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:<float>"
               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