KhronosGroup / KhronosGroup/SPIRV-Tools
Problem combining compute shaders with spirv-link
- Dominant language
- C++
- Stars
- 1.4k
- Forks
- 709
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 28
Description
I have a shader similar to this:
```
#version 450
#define HORIZONTAL 1
#define VERTICAL 2
layout (binding = 0, r16) uniform image2D image;
#if DIRECTION == HORIZONTAL
layout (local_size_x = 1, local_size_y = 17) in;
#elif DIRECTION == VERTICAL
layout (local_size_x = 1, local_size_y = 33) in;
#endif
void main() {
#if DIRECTION == HORIZONTAL
vec4 c = vec4(0.3, 0, 0, 1.0);
#elif DIRECTION == VERTICAL
vec4 c = vec4(0.7, 0, 0, 1.0);
#endif
for (int x = 0; x < imageSize(image).x; x++) {
imageStore(image, ivec2(x, gl_GlobalInvocationID.y), c);
}
}
```
I compile it with a following commands:
```
glslangValidator -V -Os -DDIRECTION=1 -e main_horizontal --source-entrypoint main src\blur.comp -o blur_hor.comp.spv
glslangValidator -V -Os -DDIRECTION=2 -e main_vertical --source-entrypoint main src\blur.comp -o blur_vert.comp.spv
```
And link with `spirv-link`:
`spirv-link blur_hor.comp.spv blur_vert.comp.spv -o blur.comp.spv`
**The problem:** when I run the combined shader `blur.comp.spv` with an entry-point `main_horizontal` and `cmd.dispatch(1, 1, 1)` I expect to see 17 dark-grey lines on top of the image. I see 33 dark-grey lines instead.
When I run the `blur_hor.comp.spv` shader I get 17 dark-grey lines on top of the image (as expected).
It seems that local workgroup specification is combined incorrectly. Here is the disassembly of the combined shader:
```
; SPIR-V
; Version: 1.0
; Generator: Khronos; 17
; Bound: 69
; Schema: 0
OpCapability Shader
OpCapability StorageImageExtendedFormats
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main_horizontal "main_horizontal" %gl_GlobalInvocationID
OpEntryPoint GLCompute %main_vertical "main_vertical" %gl_GlobalInvocationID_0
OpExecutionMode %main_horizontal LocalSize 1 17 1
OpExecutionMode %main_vertical LocalSize 1 33 1
OpSource GLSL 450
OpSource GLSL 450
OpName %main_horizontal "main_horizontal"
OpName %image "image"
OpName %gl_GlobalInvocationID "gl_GlobalInvocationID"
OpName %main_vertical "main_vertical"
OpName %image_0 "image"
OpName %gl_GlobalInvocationID_0 "gl_GlobalInvocationID"
OpDecorate %image DescriptorSet 0
OpDecorate %image Binding 0
OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
OpDecorate %image_0 DescriptorSet 0
OpDecorate %image_0 Binding 0
OpDecorate %gl_GlobalInvocationID_0 BuiltIn GlobalInvocationId
OpDecorate %gl_WorkGroupSize_0 BuiltIn WorkgroupSize
%void = OpTypeVoid
%11 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%float_0_300000012 = OpConstant %float 0.300000012
%float_0 = OpConstant %float 0
%float_1 = OpConstant %float 1
%17 = OpConstantComposite %v4float %float_0_300000012 %float_0 %float_0 %float_1
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%20 = OpTypeImage %float 2D 0 0 0 2 R16
%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20
%image = OpVariable %_ptr_UniformConstant_20 UniformConstant
%v2int = OpTypeVector %int 2
%uint = OpTypeInt 32 0
%bool = OpTypeBool
%v3uint = OpTypeVector %uint 3
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
%uint_1 = OpConstant %uint 1
%_ptr_Input_uint = OpTypePointer Input %uint
%int_1 = OpConstant %int 1
%uint_17 = OpConstant %uint 17
%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_17 %uint_1
%float_0_699999988 = OpConstant %float 0.699999988
%float_0_0 = OpConstant %float 0
%float_1_0 = OpConstant %float 1
%34 = OpConstantComposite %v4float %float_0_699999988 %float_0_0 %float_0_0 %float_1_0
%int_0_0 = OpConstant %int 0
%image_0 = OpVariable %_ptr_UniformConstant_20 UniformConstant
%gl_GlobalInvocationID_0 = OpVariable %_ptr_Input_v3uint Input
%uint_1_0 = OpConstant %uint 1
%int_1_0 = OpConstant %int 1
%uint_33 = OpConstant %uint 33
%gl_WorkGroupSize_0 = OpConstantComposite %v3uint %uint_1_0 %uint_33 %uint_1_0
%main_horizontal = OpFunction %void None %11
%39 = OpLabel
OpBranch %40
%40 = OpLabel
%41 = OpPhi %int %int_0 %39 %42 %43
%44 = OpLoad %20 %image
%45 = OpImageQuerySize %v2int %44
%46 = OpCompositeExtract %int %45 0
%47 = OpSLessThan %bool %41 %46
OpLoopMerge %48 %43 None
OpBranchConditional %47 %43 %48
%43 = OpLabel
%49 = OpLoad %20 %image
%50 = OpAccessChain %_ptr_Input_uint %gl_GlobalInvocationID %uint_1
%51 = OpLoad %uint %50
%52 = OpBitcast %int %51
%53 = OpCompositeConstruct %v2int %41 %52
OpImageWrite %49 %53 %17
%42 = OpIAdd %int %41 %int_1
OpBranch %40
%48 = OpLabel
OpReturn
OpFunctionEnd
%main_vertical = OpFunction %void None %11
%54 = OpLabel
OpBranch %55
%55 = OpLabel
%56 = OpPhi %int %int_0_0 %54 %57 %58
%59 = OpLoad %20 %image_0
%60 = OpImageQuerySize %v2int %59
%61 = OpCompositeExtract %int %60 0
%62 = OpSLessThan %bool %56 %61
OpLoopMerge %63 %58 None
OpBranchConditional %62 %58 %63
%58 = OpLabel
%64 = OpLoad %20 %image_0
%65 = OpAccessChain %_ptr_Input_uint %gl_GlobalInvocationID_0 %uint_1_0
%66 = OpLoad %uint %65
%67 = OpBitcast %int %66
%68 = OpCompositeConstruct %v2int %56 %67
OpImageWrite %64 %68 %34
%57 = OpIAdd %int %56 %int_1_0
OpBranch %55
%63 = OpLabel
OpReturn
OpFunctionEnd
```
I'm not an expert in SPIR-V so I can't figure out is the disassembly is correct. At least `OpExecutionMode` looks correct to me.
I am using `SPIRV-Tools v2020.1-dev v2019.5-13-g8aa42393` and Vulkan SDK 1.1.126
Contributor guide
Research direction
Reproduce the issue with the two glslangValidator commands followed by spirv-link, then inspect the combined module's OpEntryPoint and OpExecutionMode records for the selected entry point. Compare dispatch behavior with the separately compiled module; done means identifying and correcting the linker behavior, with a regression test covering both compute entry points.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100