external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmSignedOpTests.cpp \
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmSpirvVersion1p4Tests.cpp \
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmSpirvVersionTests.cpp \
+ external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTerminateInvocationTests.cpp \
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTests.cpp \
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTrinaryMinMaxTests.cpp \
external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmTypeTests.cpp \
dEQP-VK.spirv_assembly.instruction.amd_trinary_minmax.mid3.f64.vec2
dEQP-VK.spirv_assembly.instruction.amd_trinary_minmax.mid3.f64.vec3
dEQP-VK.spirv_assembly.instruction.amd_trinary_minmax.mid3.f64.vec4
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_output_write
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_output_write_before_terminate
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_ssbo_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_ssbo_atomic
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.ssbo_store_before_terminate
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_image_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_image_atomic
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_null_pointer_load
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_null_pointer_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_out_of_bounds_load
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_out_of_bounds_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_out_of_bounds_atomic
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.terminate_loop
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.subgroup_ballot
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.subgroup_vote
dEQP-VK.spirv_assembly.type.scalar.i8.negate_comp
dEQP-VK.spirv_assembly.type.scalar.i8.add_comp
dEQP-VK.spirv_assembly.type.scalar.i8.sub_comp
dEQP-VK.spirv_assembly.instruction.amd_trinary_minmax.mid3.f64.vec2
dEQP-VK.spirv_assembly.instruction.amd_trinary_minmax.mid3.f64.vec3
dEQP-VK.spirv_assembly.instruction.amd_trinary_minmax.mid3.f64.vec4
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_output_write
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_output_write_before_terminate
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_ssbo_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_ssbo_atomic
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.ssbo_store_before_terminate
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_image_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_image_atomic
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_null_pointer_load
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_null_pointer_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_out_of_bounds_load
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_out_of_bounds_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_out_of_bounds_atomic
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.terminate_loop
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.subgroup_ballot
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.subgroup_vote
dEQP-VK.spirv_assembly.type.scalar.i8.negate_vert
dEQP-VK.spirv_assembly.type.scalar.i8.negate_tessc
dEQP-VK.spirv_assembly.type.scalar.i8.negate_tesse
GitRepo(
"https://github.com/KhronosGroup/SPIRV-Tools.git",
None,
- "4b07d50cd9a0a537ccb28252227f87d36273cf53",
+ "f7da527757140ae701be58274ce6db2f4234d9ff",
"spirv-tools"),
GitRepo(
"https://github.com/KhronosGroup/glslang.git",
GitRepo(
"https://github.com/KhronosGroup/SPIRV-Headers.git",
None,
- "d4e76fb323745e81677ee4181986c983bf5e4d88",
+ "7845730cab6ebbdeb621e7349b7dc1a59c3377be",
"spirv-headers"),
GitRepo(
"https://github.com/google/amber.git",
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0, r32i) uniform iimage2D im2d;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;
+; imageAtomicAdd(im2d, ivec2(x_coord, y_coord), x_coord);
+;}
+OpCapability Shader
+OpExtension "SPV_KHR_terminate_invocation"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %im2d DescriptorSet 0
+OpDecorate %im2d Binding 0
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%device = OpConstant %int 1
+%relaxed = OpConstant %int 0
+%int2 = OpTypeVector %int 2
+%int4 = OpTypeVector %int 4
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%image = OpTypeImage %int 2D 0 0 0 2 R32i
+%ptr_image_uniform = OpTypePointer UniformConstant %image
+%im2d = OpVariable %ptr_image_uniform UniformConstant
+%ptr_int_image = OpTypePointer Image %int
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%im_coord = OpCompositeConstruct %int2 %x %y
+%im_ptr = OpImageTexelPointer %ptr_int_image %im2d %im_coord %int_0
+%old = OpAtomicIAdd %int %im_ptr %device %relaxed %x
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+IMAGE a_buf DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage_image DESCRIPTOR_SET 0 BINDING 0
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf IDX 0 EQ 0 1 0 3 0 5 0 7
+EXPECT a_buf IDX 32 EQ 0 1 2 3 4 5 6 7
+EXPECT a_buf IDX 64 EQ 0 1 0 3 0 5 0 7
+EXPECT a_buf IDX 96 EQ 0 1 2 3 4 5 6 7
+EXPECT a_buf IDX 128 EQ 0 1 0 3 0 5 0 7
+EXPECT a_buf IDX 160 EQ 0 1 2 3 4 5 6 7
+EXPECT a_buf IDX 192 EQ 0 1 0 3 0 5 0 7
+EXPECT a_buf IDX 224 EQ 0 1 2 3 4 5 6 7
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0, r32i) uniform iimage2D im2d;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;
+; ivec4 data = ivec4(x_coord, 0, 0, 0);
+; imageStore(im2d, ivec2(x_coord, y_coord), data);
+;}
+OpCapability Shader
+OpExtension "SPV_KHR_terminate_invocation"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %im2d DescriptorSet 0
+OpDecorate %im2d Binding 0
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%int2 = OpTypeVector %int 2
+%int4 = OpTypeVector %int 4
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%image = OpTypeImage %int 2D 0 0 0 2 R32i
+%ptr_image_uniform = OpTypePointer UniformConstant %image
+%im2d = OpVariable %ptr_image_uniform UniformConstant
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%im_data = OpCompositeConstruct %int4 %x %int_0 %int_0 %int_0
+%im_coord = OpCompositeConstruct %int2 %x %y
+%ld_im2d = OpLoad %image %im2d
+OpImageWrite %ld_im2d %im_coord %im_data
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+IMAGE a_buf DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage_image DESCRIPTOR_SET 0 BINDING 0
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf IDX 0 EQ 0 1 0 3 0 5 0 7
+EXPECT a_buf IDX 32 EQ 0 1 2 3 4 5 6 7
+EXPECT a_buf IDX 64 EQ 0 1 0 3 0 5 0 7
+EXPECT a_buf IDX 96 EQ 0 1 2 3 4 5 6 7
+EXPECT a_buf IDX 128 EQ 0 1 0 3 0 5 0 7
+EXPECT a_buf IDX 160 EQ 0 1 2 3 4 5 6 7
+EXPECT a_buf IDX 192 EQ 0 1 0 3 0 5 0 7
+EXPECT a_buf IDX 224 EQ 0 1 2 3 4 5 6 7
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0) buffer A { uint a[]; } a;
+;layout(set = 0, binding = 1) buffer B { uint b[]; } b;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; int* b_ptr = &b.b[x_coord + 8 * y_coord];
+; if (combined == int(gl_FragCoord.z)) {
+; b_ptr = nullptr;
+; terminateInvocation;
+; }
+;
+; a.a[x_coord + 8 * y_coord] = *b_ptr;;
+;}
+OpCapability Shader
+OpCapability VariablePointersStorageBuffer
+OpExtension "SPV_KHR_terminate_invocation"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpExtension "SPV_KHR_variable_pointers"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %a DescriptorSet 0
+OpDecorate %a Binding 0
+OpDecorate %b DescriptorSet 0
+OpDecorate %b Binding 1
+OpDecorate %a_block Block
+OpMemberDecorate %a_block 0 Offset 0
+OpDecorate %rta ArrayStride 4
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%rta = OpTypeRuntimeArray %int
+%a_block = OpTypeStruct %rta
+%ptr_int_ssbo = OpTypePointer StorageBuffer %int
+%ptr_a_ssbo = OpTypePointer StorageBuffer %a_block
+%a = OpVariable %ptr_a_ssbo StorageBuffer
+%b = OpVariable %ptr_a_ssbo StorageBuffer
+%nullptr = OpConstantNull %ptr_int_ssbo
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+%offset = OpIMul %int %y %int_8
+%idx = OpIAdd %int %x %offset
+%b_ptr = OpAccessChain %ptr_int_ssbo %b %int_0 %idx
+%b_sel = OpSelect %ptr_int_ssbo %cmp %nullptr %b_ptr
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%a_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %idx
+OpCopyMemory %a_gep %b_sel
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+BUFFER a_buf DATA_TYPE int32 SIZE 64 FILL 0
+BUFFER b_buf DATA_TYPE int32 SIZE 64 SERIES_FROM 0 INC_BY 1
+BUFFER expect_buf DATA_TYPE int32 DATA
+ 0 1 0 3 0 5 0 7
+ 8 9 10 11 12 13 14 15
+ 0 17 0 19 0 21 0 23
+24 25 26 27 28 29 30 31
+ 0 33 0 35 0 37 0 39
+40 41 42 43 44 45 46 47
+ 0 49 0 51 0 53 0 55
+56 57 58 59 60 61 62 63
+END
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage DESCRIPTOR_SET 0 BINDING 0
+ BIND BUFFER b_buf AS storage DESCRIPTOR_SET 0 BINDING 1
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf EQ_BUFFER expect_buf
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0) buffer A { uint a[]; } a;
+;layout(set = 0, binding = 1) buffer B { uint b[]; } b;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; int* a_ptr = &a.a[x_coord + 8 * y_coord];
+; if (combined == int(gl_FragCoord.z)) {
+; a_ptr = nullptr;
+; terminateInvocation;
+; }
+;
+; *a_ptr = b.b[x_coord + 8 * y_coord];
+;}
+OpCapability Shader
+OpCapability VariablePointersStorageBuffer
+OpExtension "SPV_KHR_terminate_invocation"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpExtension "SPV_KHR_variable_pointers"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %a DescriptorSet 0
+OpDecorate %a Binding 0
+OpDecorate %b DescriptorSet 0
+OpDecorate %b Binding 1
+OpDecorate %a_block Block
+OpMemberDecorate %a_block 0 Offset 0
+OpDecorate %rta ArrayStride 4
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%rta = OpTypeRuntimeArray %int
+%a_block = OpTypeStruct %rta
+%ptr_int_ssbo = OpTypePointer StorageBuffer %int
+%ptr_a_ssbo = OpTypePointer StorageBuffer %a_block
+%a = OpVariable %ptr_a_ssbo StorageBuffer
+%b = OpVariable %ptr_a_ssbo StorageBuffer
+%nullptr = OpConstantNull %ptr_int_ssbo
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+%offset = OpIMul %int %y %int_8
+%idx = OpIAdd %int %x %offset
+%b_ptr = OpAccessChain %ptr_int_ssbo %b %int_0 %idx
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%a_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %idx
+%a_sel = OpSelect %ptr_int_ssbo %cmp %nullptr %a_gep
+OpCopyMemory %a_sel %b_ptr
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+BUFFER a_buf DATA_TYPE int32 SIZE 64 FILL 0
+BUFFER b_buf DATA_TYPE int32 SIZE 64 SERIES_FROM 0 INC_BY 1
+BUFFER expect_buf DATA_TYPE int32 DATA
+ 0 1 0 3 0 5 0 7
+ 8 9 10 11 12 13 14 15
+ 0 17 0 19 0 21 0 23
+24 25 26 27 28 29 30 31
+ 0 33 0 35 0 37 0 39
+40 41 42 43 44 45 46 47
+ 0 49 0 51 0 53 0 55
+56 57 58 59 60 61 62 63
+END
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage DESCRIPTOR_SET 0 BINDING 0
+ BIND BUFFER b_buf AS storage DESCRIPTOR_SET 0 BINDING 1
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf EQ_BUFFER expect_buf
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0) buffer A { uint a[]; } a;
+;layout(set = 0, binding = 1) buffer B { uint b[]; } b;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int add = (x_coord & 0x1) + (y_coord & 0x1);
+; int combined = add + in_data;
+; if (combined == int(gl_FragCoord.z)) {
+; terminateInvocation;
+; }
+;
+; int* a_ptr = (add == 0) ? &a.a[0] + a.a.length() : &a.a[x_coord + 8 * y_coord];
+; atomicAdd(*a_ptr, b.b[x_coord + 8 * y_coord]);
+;}
+OpCapability Shader
+OpCapability VariablePointersStorageBuffer
+OpExtension "SPV_KHR_terminate_invocation"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpExtension "SPV_KHR_variable_pointers"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %a DescriptorSet 0
+OpDecorate %a Binding 0
+OpDecorate %b DescriptorSet 0
+OpDecorate %b Binding 1
+OpDecorate %a_block Block
+OpMemberDecorate %a_block 0 Offset 0
+OpDecorate %rta ArrayStride 4
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%device = OpConstant %int 1
+%relaxed = OpConstant %int 0
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%rta = OpTypeRuntimeArray %int
+%a_block = OpTypeStruct %rta
+%ptr_int_ssbo = OpTypePointer StorageBuffer %int
+%ptr_a_ssbo = OpTypePointer StorageBuffer %a_block
+%a = OpVariable %ptr_a_ssbo StorageBuffer
+%b = OpVariable %ptr_a_ssbo StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+%offset = OpIMul %int %y %int_8
+%idx = OpIAdd %int %x %offset
+%b_ptr = OpAccessChain %ptr_int_ssbo %b %int_0 %idx
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%a_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %idx
+%a_len = OpArrayLength %int %a 0
+%a_0_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %int_0
+%oob_ptr = OpPtrAccessChain %ptr_int_ssbo %a_0_gep %a_len
+%cmp2 = OpIEqual %bool %add %int_0
+%a_sel = OpSelect %ptr_int_ssbo %cmp2 %oob_ptr %a_gep
+%b_val = OpLoad %int %b_ptr
+%old = OpAtomicIAdd %int %a_sel %device %relaxed %b_val
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+BUFFER a_buf DATA_TYPE int32 SIZE 64 FILL 0
+BUFFER b_buf DATA_TYPE int32 SIZE 64 SERIES_FROM 0 INC_BY 1
+BUFFER expect_buf DATA_TYPE int32 DATA
+ 0 1 0 3 0 5 0 7
+ 8 9 10 11 12 13 14 15
+ 0 17 0 19 0 21 0 23
+24 25 26 27 28 29 30 31
+ 0 33 0 35 0 37 0 39
+40 41 42 43 44 45 46 47
+ 0 49 0 51 0 53 0 55
+56 57 58 59 60 61 62 63
+END
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage DESCRIPTOR_SET 0 BINDING 0
+ BIND BUFFER b_buf AS storage DESCRIPTOR_SET 0 BINDING 1
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf EQ_BUFFER expect_buf
+
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0) buffer A { uint a[]; } a;
+;layout(set = 0, binding = 1) buffer B { uint b[]; } b;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int add = (x_coord & 0x1) + (y_coord & 0x1);
+; int combined = add + in_data;
+; if (combined == int(gl_FragCoord.z)) {
+; terminateInvocation;
+; }
+;
+; int* b_ptr = (add == 0) ? &b.b[0] + b.b.length() : &b.b[x_coord + 8 * y_coord];
+; a.a[x_coord + 8 * y_coord] = *b_ptr;;
+;}
+OpCapability Shader
+OpCapability VariablePointersStorageBuffer
+OpExtension "SPV_KHR_terminate_invocation"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpExtension "SPV_KHR_variable_pointers"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %a DescriptorSet 0
+OpDecorate %a Binding 0
+OpDecorate %b DescriptorSet 0
+OpDecorate %b Binding 1
+OpDecorate %a_block Block
+OpMemberDecorate %a_block 0 Offset 0
+OpDecorate %rta ArrayStride 4
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%rta = OpTypeRuntimeArray %int
+%a_block = OpTypeStruct %rta
+%ptr_int_ssbo = OpTypePointer StorageBuffer %int
+%ptr_a_ssbo = OpTypePointer StorageBuffer %a_block
+%a = OpVariable %ptr_a_ssbo StorageBuffer
+%b = OpVariable %ptr_a_ssbo StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+%offset = OpIMul %int %y %int_8
+%idx = OpIAdd %int %x %offset
+%b_ptr = OpAccessChain %ptr_int_ssbo %b %int_0 %idx
+%len = OpArrayLength %int %b 0
+%b_0_ptr = OpAccessChain %ptr_int_ssbo %b %int_0 %int_0
+%oob_ptr = OpPtrAccessChain %ptr_int_ssbo %b_0_ptr %len
+%cmp2 = OpIEqual %bool %add %int_0
+%b_sel = OpSelect %ptr_int_ssbo %cmp2 %oob_ptr %b_ptr
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%a_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %idx
+OpCopyMemory %a_gep %b_sel
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+BUFFER a_buf DATA_TYPE int32 SIZE 64 FILL 0
+BUFFER b_buf DATA_TYPE int32 SIZE 64 SERIES_FROM 0 INC_BY 1
+BUFFER expect_buf DATA_TYPE int32 DATA
+ 0 1 0 3 0 5 0 7
+ 8 9 10 11 12 13 14 15
+ 0 17 0 19 0 21 0 23
+24 25 26 27 28 29 30 31
+ 0 33 0 35 0 37 0 39
+40 41 42 43 44 45 46 47
+ 0 49 0 51 0 53 0 55
+56 57 58 59 60 61 62 63
+END
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage DESCRIPTOR_SET 0 BINDING 0
+ BIND BUFFER b_buf AS storage DESCRIPTOR_SET 0 BINDING 1
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf EQ_BUFFER expect_buf
+
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0) buffer A { uint a[]; } a;
+;layout(set = 0, binding = 1) buffer B { uint b[]; } b;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int add = (x_coord & 0x1) + (y_coord & 0x1);
+; int combined = add + in_data;
+; if (combined == int(gl_FragCoord.z)) {
+; terminateInvocation;
+; }
+;
+; int* a_ptr = (add == 0) ? &a.a[0] + a.a.length() : &a.a[x_coord + 8 * y_coord];
+; *a_ptr = b.b[x_coord + 8 * y_coord];
+;}
+OpCapability Shader
+OpCapability VariablePointersStorageBuffer
+OpExtension "SPV_KHR_terminate_invocation"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpExtension "SPV_KHR_variable_pointers"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %a DescriptorSet 0
+OpDecorate %a Binding 0
+OpDecorate %b DescriptorSet 0
+OpDecorate %b Binding 1
+OpDecorate %a_block Block
+OpMemberDecorate %a_block 0 Offset 0
+OpDecorate %rta ArrayStride 4
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%rta = OpTypeRuntimeArray %int
+%a_block = OpTypeStruct %rta
+%ptr_int_ssbo = OpTypePointer StorageBuffer %int
+%ptr_a_ssbo = OpTypePointer StorageBuffer %a_block
+%a = OpVariable %ptr_a_ssbo StorageBuffer
+%b = OpVariable %ptr_a_ssbo StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+%offset = OpIMul %int %y %int_8
+%idx = OpIAdd %int %x %offset
+%b_ptr = OpAccessChain %ptr_int_ssbo %b %int_0 %idx
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%a_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %idx
+%a_len = OpArrayLength %int %a 0
+%a_0_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %int_0
+%oob_ptr = OpPtrAccessChain %ptr_int_ssbo %a_0_gep %a_len
+%cmp2 = OpIEqual %bool %add %int_0
+%a_sel = OpSelect %ptr_int_ssbo %cmp2 %oob_ptr %a_gep
+OpCopyMemory %a_sel %b_ptr
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+BUFFER a_buf DATA_TYPE int32 SIZE 64 FILL 0
+BUFFER b_buf DATA_TYPE int32 SIZE 64 SERIES_FROM 0 INC_BY 1
+BUFFER expect_buf DATA_TYPE int32 DATA
+ 0 1 0 3 0 5 0 7
+ 8 9 10 11 12 13 14 15
+ 0 17 0 19 0 21 0 23
+24 25 26 27 28 29 30 31
+ 0 33 0 35 0 37 0 39
+40 41 42 43 44 45 46 47
+ 0 49 0 51 0 53 0 55
+56 57 58 59 60 61 62 63
+END
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage DESCRIPTOR_SET 0 BINDING 0
+ BIND BUFFER b_buf AS storage DESCRIPTOR_SET 0 BINDING 1
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf EQ_BUFFER expect_buf
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;
+; out_data = 1;
+;}
+OpCapability Shader
+OpExtension "SPV_KHR_terminate_invocation"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_1 = OpConstant %int 1
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+OpStore %out_data %int_1
+OpReturn
+OpFunctionEnd
+END
+
+SHADER vertex passthrough PASSTHROUGH
+SHADER fragment expect_fs GLSL
+#version 450
+
+layout(location = 0) out int out_data;
+void main() {
+ bool x_is_odd = (int(gl_FragCoord.x) & 0x1) == 1;
+ bool y_is_odd = (int(gl_FragCoord.y) & 0x1) == 1;
+ out_data = (x_is_odd || y_is_odd) ? 1 : 0;
+}
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+IMAGE expect_frame DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+END
+
+PIPELINE graphics expect_pipe
+ ATTACH passthrough
+ ATTACH expect_fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ BIND BUFFER expect_frame AS color LOCATION 0
+END
+
+RUN expect_pipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT out_data EQ_BUFFER expect_frame
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; out_data = 1;
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;}
+OpCapability Shader
+OpExtension "SPV_KHR_terminate_invocation"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_1 = OpConstant %int 1
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+OpStore %out_data %int_1
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+OpReturn
+OpFunctionEnd
+END
+
+SHADER vertex passthrough PASSTHROUGH
+SHADER fragment expect_fs GLSL
+#version 450
+
+layout(location = 0) out int out_data;
+void main() {
+ bool x_is_odd = (int(gl_FragCoord.x) & 0x1) == 1;
+ bool y_is_odd = (int(gl_FragCoord.y) & 0x1) == 1;
+ out_data = (x_is_odd || y_is_odd) ? 1 : 0;
+}
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+IMAGE expect_frame DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+END
+
+PIPELINE graphics expect_pipe
+ ATTACH passthrough
+ ATTACH expect_fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ BIND BUFFER expect_frame AS color LOCATION 0
+END
+
+RUN expect_pipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT out_data EQ_BUFFER expect_frame
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0) buffer A { uint a[]; } a;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;
+; atomicAdd(a.a[x_coord + 8 * y_coord], x_coord);
+;}
+OpCapability Shader
+OpExtension "SPV_KHR_terminate_invocation"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %a DescriptorSet 0
+OpDecorate %a Binding 0
+OpDecorate %a_block Block
+OpMemberDecorate %a_block 0 Offset 0
+OpDecorate %rta ArrayStride 4
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%device = OpConstant %int 1
+%relaxed = OpConstant %int 0
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%rta = OpTypeRuntimeArray %int
+%a_block = OpTypeStruct %rta
+%ptr_int_ssbo = OpTypePointer StorageBuffer %int
+%ptr_a_ssbo = OpTypePointer StorageBuffer %a_block
+%a = OpVariable %ptr_a_ssbo StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%offset = OpIMul %int %y %int_8
+%idx = OpIAdd %int %x %offset
+%a_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %idx
+%old = OpAtomicIAdd %int %a_gep %device %relaxed %x
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+BUFFER a_buf DATA_TYPE int32 SIZE 64 FILL 0
+BUFFER expect_buf DATA_TYPE int32 DATA
+0 1 0 3 0 5 0 7
+0 1 2 3 4 5 6 7
+0 1 0 3 0 5 0 7
+0 1 2 3 4 5 6 7
+0 1 0 3 0 5 0 7
+0 1 2 3 4 5 6 7
+0 1 0 3 0 5 0 7
+0 1 2 3 4 5 6 7
+END
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage DESCRIPTOR_SET 0 BINDING 0
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf EQ_BUFFER expect_buf
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0) buffer A { uint a[]; } a;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;
+; a.a[x_coord + 8 * y_coord] = x_coord;
+;}
+OpCapability Shader
+OpExtension "SPV_KHR_terminate_invocation"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %a DescriptorSet 0
+OpDecorate %a Binding 0
+OpDecorate %a_block Block
+OpMemberDecorate %a_block 0 Offset 0
+OpDecorate %rta ArrayStride 4
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%rta = OpTypeRuntimeArray %int
+%a_block = OpTypeStruct %rta
+%ptr_int_ssbo = OpTypePointer StorageBuffer %int
+%ptr_a_ssbo = OpTypePointer StorageBuffer %a_block
+%a = OpVariable %ptr_a_ssbo StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%offset = OpIMul %int %y %int_8
+%idx = OpIAdd %int %x %offset
+%a_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %idx
+OpStore %a_gep %x
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+BUFFER a_buf DATA_TYPE int32 SIZE 64 FILL 0
+BUFFER expect_buf DATA_TYPE int32 DATA
+0 1 0 3 0 5 0 7
+0 1 2 3 4 5 6 7
+0 1 0 3 0 5 0 7
+0 1 2 3 4 5 6 7
+0 1 0 3 0 5 0 7
+0 1 2 3 4 5 6 7
+0 1 0 3 0 5 0 7
+0 1 2 3 4 5 6 7
+END
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage DESCRIPTOR_SET 0 BINDING 0
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf EQ_BUFFER expect_buf
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0) buffer A { uint a[]; } a;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; atomicAdd(a.a[x_coord + 8 * y_coord], x_coord);
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;}
+OpCapability Shader
+OpExtension "SPV_KHR_terminate_invocation"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %a DescriptorSet 0
+OpDecorate %a Binding 0
+OpDecorate %a_block Block
+OpMemberDecorate %a_block 0 Offset 0
+OpDecorate %rta ArrayStride 4
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%device = OpConstant %int 1
+%relaxed = OpConstant %int 0
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%rta = OpTypeRuntimeArray %int
+%a_block = OpTypeStruct %rta
+%ptr_int_ssbo = OpTypePointer StorageBuffer %int
+%ptr_a_ssbo = OpTypePointer StorageBuffer %a_block
+%a = OpVariable %ptr_a_ssbo StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%offset = OpIMul %int %y %int_8
+%idx = OpIAdd %int %x %offset
+%a_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %idx
+%old = OpAtomicIAdd %int %a_gep %device %relaxed %x
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+BUFFER a_buf DATA_TYPE int32 SIZE 64 FILL 0
+BUFFER expect_buf DATA_TYPE int32 DATA
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+END
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage DESCRIPTOR_SET 0 BINDING 0
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf EQ_BUFFER expect_buf
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#pragma GL_EXT_terminate_invocation : enable
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;layout(set = 0, binding = 0) buffer A { uint a[]; } a;
+;void main() {
+; out_data = 1;
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; a.a[x_coord + 8 * y_coord] = x_coord;
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;}
+OpCapability Shader
+OpExtension "SPV_KHR_terminate_invocation"
+OpExtension "SPV_KHR_storage_buffer_storage_class"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %a DescriptorSet 0
+OpDecorate %a Binding 0
+OpDecorate %a_block Block
+OpMemberDecorate %a_block 0 Offset 0
+OpDecorate %rta ArrayStride 4
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_8 = OpConstant %int 8
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%rta = OpTypeRuntimeArray %int
+%a_block = OpTypeStruct %rta
+%ptr_int_ssbo = OpTypePointer StorageBuffer %int
+%ptr_a_ssbo = OpTypePointer StorageBuffer %a_block
+%a = OpVariable %ptr_a_ssbo StorageBuffer
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+OpStore %out_data %int_1
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%offset = OpIMul %int %y %int_8
+%idx = OpIAdd %int %x %offset
+%a_gep = OpAccessChain %ptr_int_ssbo %a %int_0 %idx
+OpStore %a_gep %x
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+OpReturn
+OpFunctionEnd
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+BUFFER a_buf DATA_TYPE int32 SIZE 64 FILL 0
+BUFFER expect_buf DATA_TYPE int32 DATA
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+0 1 2 3 4 5 6 7
+END
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+ BIND BUFFER a_buf AS storage DESCRIPTOR_SET 0 BINDING 0
+END
+
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT a_buf EQ_BUFFER expect_buf
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#extension GL_KHR_shader_subgroup_ballot : enable
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;
+;void main() {
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; bool cond = combined == int(gl_FragCoord.z);
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;
+; int quad_idx = (x_coord & 0x1) + 2 * (y_coord & 0x1);
+; uvec4 b = subgroupBallot(true);
+; uint element;
+; if (gl_SubgroupInvocationID < 32)
+; element = b.x;
+; else if (gl_SubgroupInvocationID < 64)
+; element = b.y;
+; else if (gl_SubgroupInvocationID < 96)
+; element = b.z;
+; else
+; element = b.w;
+; uint base_bit = (gl_SubgroupInvocationID - quad_idx) % 32;
+; bool check_quad_idx_0 = ((element >> base_bit) & 0x1) == 0;
+; out_data = check_quad_idx_0 ? 1 : 0;
+;
+;}
+OpCapability Shader
+OpCapability GroupNonUniformBallot
+OpExtension "SPV_KHR_terminate_invocation"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data %subgroupID
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %subgroupID Flat
+OpDecorate %subgroupID BuiltIn SubgroupLocalInvocationId
+%void = OpTypeVoid
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_2 = OpConstant %int 2
+%int_3 = OpConstant %int 3
+%int_32 = OpConstant %int 32
+%int_64 = OpConstant %int 64
+%int_96 = OpConstant %int 96
+%subgroup = OpConstant %int 3
+%int4 = OpTypeVector %int 4
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%subgroupID = OpVariable %ptr_int_input Input
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%y_2 = OpIMul %int %int_2 %y_and_1
+%quad_idx = OpIAdd %int %x_and_1 %y_2
+%b = OpGroupNonUniformBallot %int4 %subgroup %true
+%sid = OpLoad %int %subgroupID
+%less_than_32 = OpULessThan %bool %sid %int_32
+OpSelectionMerge %merge_32 None
+OpBranchConditional %less_than_32 %then_32 %else_32
+%then_32 = OpLabel
+%element_0 = OpCompositeExtract %int %b 0
+OpBranch %merge_32
+%else_32 = OpLabel
+%less_than_64 = OpULessThan %bool %sid %int_64
+OpSelectionMerge %merge_64 None
+OpBranchConditional %less_than_64 %then_64 %else_64
+%then_64 = OpLabel
+%element_1 = OpCompositeExtract %int %b 1
+OpBranch %merge_64
+%else_64 = OpLabel
+%less_than_96 = OpULessThan %bool %sid %int_96
+%element_2 = OpCompositeExtract %int %b 2
+%element_3 = OpCompositeExtract %int %b 3
+%sel_96 = OpSelect %int %less_than_96 %element_2 %element_3
+OpBranch %merge_64
+%merge_64 = OpLabel
+%phi_64 = OpPhi %int %element_1 %then_64 %sel_96 %else_64
+OpBranch %merge_32
+%merge_32 = OpLabel
+%phi_32 = OpPhi %int %element_0 %then_32 %phi_64 %merge_64
+%bit = OpISub %int %sid %quad_idx
+%base_bit = OpUMod %int %bit %int_32
+%idx_0_shift = OpShiftRightLogical %int %phi_32 %base_bit
+%idx_0_shift_and_1 = OpBitwiseAnd %int %idx_0_shift %int_1
+%idx_0_check = OpIEqual %bool %idx_0_shift_and_1 %int_0
+%out_val = OpSelect %int %idx_0_check %int_1 %int_0
+OpStore %out_data %out_val
+OpReturn
+OpFunctionEnd
+END
+
+SHADER vertex passthrough PASSTHROUGH
+SHADER fragment expect_fs GLSL
+#version 450
+
+layout(location = 0) out int out_data;
+void main() {
+ bool x_is_odd = (int(gl_FragCoord.x) & 0x1) == 1;
+ bool y_is_odd = (int(gl_FragCoord.y) & 0x1) == 1;
+ out_data = (x_is_odd || y_is_odd) ? 1 : 0;
+}
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+IMAGE expect_frame DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+END
+
+PIPELINE graphics expect_pipe
+ ATTACH passthrough
+ ATTACH expect_fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ BIND BUFFER expect_frame AS color LOCATION 0
+END
+
+RUN expect_pipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT out_data EQ_BUFFER expect_frame
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;#extension GL_KHR_shader_subgroup_vote : enable
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;
+;void main() {
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; bool cond = combined == int(gl_FragCoord.z);
+; if (combined == int(gl_FragCoord.z))
+; terminateInvocation;
+;
+; bool all = subgroupAll(cond);
+; out_data = all ? 1 : 0;
+;}
+OpCapability Shader
+OpCapability GroupNonUniformVote
+OpExtension "SPV_KHR_terminate_invocation"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data %subgroupID
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+OpDecorate %subgroupID Flat
+OpDecorate %subgroupID BuiltIn SubgroupLocalInvocationId
+%void = OpTypeVoid
+%bool = OpTypeBool
+%true = OpConstantTrue %bool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%subgroup = OpConstant %int 3
+%int4 = OpTypeVector %int 4
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%subgroupID = OpVariable %ptr_int_input Input
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+%not_cmp = OpLogicalNot %bool %cmp
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+OpTerminateInvocation
+%exit = OpLabel
+%all = OpGroupNonUniformAll %bool %subgroup %not_cmp
+%sel = OpSelect %int %all %int_1 %int_0
+OpStore %out_data %sel
+OpReturn
+OpFunctionEnd
+END
+
+SHADER vertex passthrough PASSTHROUGH
+SHADER fragment expect_fs GLSL
+#version 450
+
+layout(location = 0) out int out_data;
+void main() {
+ bool x_is_odd = (int(gl_FragCoord.x) & 0x1) == 1;
+ bool y_is_odd = (int(gl_FragCoord.y) & 0x1) == 1;
+ out_data = (x_is_odd || y_is_odd) ? 1 : 0;
+}
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+IMAGE expect_frame DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+END
+
+PIPELINE graphics expect_pipe
+ ATTACH passthrough
+ ATTACH expect_fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ BIND BUFFER expect_frame AS color LOCATION 0
+END
+
+RUN expect_pipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT out_data EQ_BUFFER expect_frame
+
--- /dev/null
+#!amber
+
+SHADER vertex vs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in vec3 position;
+;layout(location = 1) in int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; gl_Position = vec4(position, 1.0);
+; out_data = int(in_data);
+;}
+OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint Vertex %main "main" %position %in_data %out_data %per_vertex
+OpDecorate %position Location 0
+OpDecorate %in_data Location 1
+OpDecorate %out_data Location 0
+OpDecorate %block Block
+OpMemberDecorate %block 0 BuiltIn Position
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%float = OpTypeFloat 32
+%float_1 = OpConstant %float 1
+%float3 = OpTypeVector %float 3
+%float4 = OpTypeVector %float 4
+%ptr_float3_input = OpTypePointer Input %float3
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%block = OpTypeStruct %float4
+%ptr_float4_output = OpTypePointer Output %float4
+%ptr_block_output = OpTypePointer Output %block
+%position = OpVariable %ptr_float3_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%per_vertex = OpVariable %ptr_block_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%ld_pos = OpLoad %float3 %position
+%out_pos = OpCompositeConstruct %float4 %ld_pos %float_1
+%out_pos_gep = OpAccessChain %ptr_float4_output %per_vertex %int_0
+OpStore %out_pos_gep %out_pos
+OpCopyMemory %out_data %in_data
+OpReturn
+OpFunctionEnd
+END
+
+SHADER fragment fs SPIRV-ASM
+;#version 450
+;
+;layout(location = 0) in flat int in_data;
+;layout(location = 0) out int out_data;
+;void main() {
+; int x_coord = int(gl_FragCoord.x);
+; int y_coord = int(gl_FragCoord.y);
+; int combined = (x_coord & 0x1) + (y_coord & 0x1) + in_data;
+; if (combined == int(gl_FragCoord.z))
+; for (int i = 0; i < 10; i += in_data)
+; terminate_invocation;
+;
+; out_data = 1;
+;}
+OpCapability Shader
+OpExtension "SPV_KHR_terminate_invocation"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %frag_coord %in_data %out_data
+OpExecutionMode %main OriginUpperLeft
+OpDecorate %frag_coord BuiltIn FragCoord
+OpDecorate %in_data Location 0
+OpDecorate %in_data Flat
+OpDecorate %out_data Location 0
+%void = OpTypeVoid
+%bool = OpTypeBool
+%int = OpTypeInt 32 0
+%int_0 = OpConstant %int 0
+%int_1 = OpConstant %int 1
+%int_10 = OpConstant %int 10
+%float = OpTypeFloat 32
+%float4 = OpTypeVector %float 4
+%ptr_int_input = OpTypePointer Input %int
+%ptr_int_output = OpTypePointer Output %int
+%ptr_float4_input = OpTypePointer Input %float4
+%frag_coord = OpVariable %ptr_float4_input Input
+%in_data = OpVariable %ptr_int_input Input
+%out_data = OpVariable %ptr_int_output Output
+%void_fn = OpTypeFunction %void
+%main = OpFunction %void None %void_fn
+%entry = OpLabel
+%coord = OpLoad %float4 %frag_coord
+%x_coord = OpCompositeExtract %float %coord 0
+%y_coord = OpCompositeExtract %float %coord 1
+%z_coord = OpCompositeExtract %float %coord 2
+%x = OpConvertFToS %int %x_coord
+%y = OpConvertFToS %int %y_coord
+%z = OpConvertFToS %int %z_coord
+%x_and_1 = OpBitwiseAnd %int %x %int_1
+%y_and_1 = OpBitwiseAnd %int %y %int_1
+%add = OpIAdd %int %x_and_1 %y_and_1
+%ld_in_data = OpLoad %int %in_data
+%combined = OpIAdd %int %add %ld_in_data
+%cmp = OpIEqual %bool %combined %z
+OpSelectionMerge %exit None
+OpBranchConditional %cmp %then %exit
+%then = OpLabel
+%i = OpPhi %int %int_0 %entry %inc %continue
+%i_cmp = OpULessThan %bool %i %int_10
+OpLoopMerge %loop_merge %continue None
+OpBranchConditional %i_cmp %body %loop_merge
+%body = OpLabel
+OpTerminateInvocation
+%continue = OpLabel
+%inc = OpIAdd %int %i %int_1
+OpBranch %then
+%loop_merge = OpLabel
+OpBranch %exit
+%exit = OpLabel
+OpStore %out_data %int_1
+OpReturn
+OpFunctionEnd
+END
+
+SHADER vertex passthrough PASSTHROUGH
+SHADER fragment expect_fs GLSL
+#version 450
+
+layout(location = 0) out int out_data;
+void main() {
+ bool x_is_odd = (int(gl_FragCoord.x) & 0x1) == 1;
+ bool y_is_odd = (int(gl_FragCoord.y) & 0x1) == 1;
+ out_data = (x_is_odd || y_is_odd) ? 1 : 0;
+}
+END
+
+BUFFER position_buf DATA_TYPE vec3<float> DATA
+-1 -1 0
+-1 1 0
+ 1 -1 0
+
+-1 1 0
+ 1 -1 0
+ 1 1 0
+END
+
+BUFFER in_data_buf DATA_TYPE int32 SIZE 6 FILL 0
+
+IMAGE out_data DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+IMAGE expect_frame DATA_TYPE int32 DIM_2D WIDTH 8 HEIGHT 8 FILL 0
+
+PIPELINE graphics gpipe
+ ATTACH vs
+ ATTACH fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ VERTEX_DATA in_data_buf LOCATION 1
+ BIND BUFFER out_data AS color LOCATION 0
+END
+
+PIPELINE graphics expect_pipe
+ ATTACH passthrough
+ ATTACH expect_fs
+
+ FRAMEBUFFER_SIZE 8 8
+ VERTEX_DATA position_buf LOCATION 0
+ BIND BUFFER expect_frame AS color LOCATION 0
+END
+
+RUN expect_pipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+RUN gpipe DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 6
+EXPECT out_data EQ_BUFFER expect_frame
+
"VK_KHR_performance_query",
"VK_KHR_shader_non_semantic_info",
"VK_KHR_copy_commands2",
+ "VK_KHR_shader_terminate_invocation",
};
nextPtr = &physicalDeviceShaderSubgroupExtendedTypesFeaturesKHR.pNext;
}
+ vk::VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR physicalDeviceShaderTerminateInvocationFeaturesKHR;
+ deMemset(&physicalDeviceShaderTerminateInvocationFeaturesKHR, 0, sizeof(physicalDeviceShaderTerminateInvocationFeaturesKHR));
+
+ if ( isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_shader_terminate_invocation")) )
+ {
+ physicalDeviceShaderTerminateInvocationFeaturesKHR.sType = getStructureType<VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR>();
+ *nextPtr = &physicalDeviceShaderTerminateInvocationFeaturesKHR;
+ nextPtr = &physicalDeviceShaderTerminateInvocationFeaturesKHR.pNext;
+ }
+
vk::VkPhysicalDeviceSubgroupSizeControlFeaturesEXT physicalDeviceSubgroupSizeControlFeaturesEXT;
deMemset(&physicalDeviceSubgroupSizeControlFeaturesEXT, 0, sizeof(physicalDeviceSubgroupSizeControlFeaturesEXT));
}
}
+ if ( isExtensionSupported(deviceExtensions, RequiredExtension("VK_KHR_shader_terminate_invocation")) )
+ {
+ if ( physicalDeviceShaderTerminateInvocationFeaturesKHR.shaderTerminateInvocation == VK_FALSE )
+ {
+ log << tcu::TestLog::Message << "Mandatory feature shaderTerminateInvocation not supported" << tcu::TestLog::EndMessage;
+ result = false;
+ }
+ }
+
return result;
}
return ctx.getDeviceFeatures().tessellationShader;
if (feature == "Features.geometryShader")
return ctx.getDeviceFeatures().geometryShader;
+ if (feature == "Features.fragmentStoresAndAtomics")
+ return ctx.getDeviceFeatures().fragmentStoresAndAtomics;
if (feature == "Features.vertexPipelineStoresAndAtomics")
return ctx.getDeviceFeatures().vertexPipelineStoresAndAtomics;
if (feature == "Features.fillModeNonSolid")
return ctx.getVariablePointersFeatures().variablePointersStorageBuffer;
if (feature == "VariablePointerFeatures.variablePointers")
return ctx.getVariablePointersFeatures().variablePointers;
+ if (feature == "SubgroupProperties.supportedStages.fragment")
+ return (ctx.getSubgroupProperties().supportedStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
+ if (feature == "SubgroupProperties.supportedOperations.vote")
+ return (ctx.getSubgroupProperties().supportedOperations & vk::VK_SUBGROUP_FEATURE_VOTE_BIT) != 0;
+ if (feature == "SubgroupProperties.supportedOperations.ballot")
+ return (ctx.getSubgroupProperties().supportedOperations & vk::VK_SUBGROUP_FEATURE_BALLOT_BIT) != 0;
std::string message = std::string("Unexpected feature name: ") + feature;
TCU_THROW(InternalError, message.c_str());
vktSpvAsm64bitCompareTests.hpp
vktSpvAsmTypeTests.cpp
vktSpvAsmTypeTests.hpp
+ vktSpvAsmTerminateInvocationTests.cpp
+ vktSpvAsmTerminateInvocationTests.hpp
vktSpvAsmTests.cpp
vktSpvAsmTests.hpp
vktSpvAsmUtils.cpp
#include "vktSpvAsmNonSemanticInfoTests.hpp"
#include "vktSpvAsm64bitCompareTests.hpp"
#include "vktSpvAsmTrinaryMinMaxTests.hpp"
+#include "vktSpvAsmTerminateInvocationTests.hpp"
#include <cmath>
#include <limits>
instructionTests->addChild(createSpirvVersion1p4Group(testCtx));
instructionTests->addChild(createFunctionParamsGroup(testCtx));
instructionTests->addChild(createTrinaryMinMaxGroup(testCtx));
+ instructionTests->addChild(createTerminateInvocationGroup(testCtx));
return instructionTests.release();
}
--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2020 Google LLC
+ * Copyright (c) 2020 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Test new features in VK_KHR_shader_terminate_invocation
+ *//*--------------------------------------------------------------------*/
+
+#include <string>
+#include <vector>
+#include <amber/amber.h>
+
+#include "tcuDefs.hpp"
+
+#include "vkDefs.hpp"
+#include "vktTestGroupUtil.hpp"
+#include "vktAmberTestCase.hpp"
+#include "vktSpvAsmTerminateInvocationTests.hpp"
+#include "vktTestGroupUtil.hpp"
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+namespace
+{
+
+struct Case
+{
+ Case(const char* b, const char* d, bool v) : basename(b), description(d), spv1p3(v), requirements() { }
+ Case(const char* b, const char* d, bool v, const std::vector<std::string>& e) : basename(b), description(d), spv1p3(v), requirements(e) { }
+ const char *basename;
+ const char *description;
+ bool spv1p3;
+ // Additional Vulkan requirements, if any.
+ std::vector<std::string> requirements;
+};
+struct CaseGroup
+{
+ CaseGroup(const char* the_data_dir) : data_dir(the_data_dir) { }
+ void add(const char* basename, const char* description, bool spv1p3)
+ {
+ cases.push_back(Case(basename, description, spv1p3));
+ }
+ void add(const char* basename, const char* description, bool spv1p3, const std::vector<std::string>& requirements)
+ {
+ cases.push_back(Case(basename, description, spv1p3, requirements));
+ }
+
+ const char* data_dir;
+ std::vector<Case> cases;
+};
+
+
+void addTestsForAmberFiles (tcu::TestCaseGroup* tests, CaseGroup group)
+{
+ tcu::TestContext& testCtx = tests->getTestContext();
+ const std::string data_dir(group.data_dir);
+ const std::string category = data_dir;
+ std::vector<Case> cases(group.cases);
+
+ for (unsigned i = 0; i < cases.size() ; ++i)
+ {
+ deUint32 vulkan_version = cases[i].spv1p3 ? VK_MAKE_VERSION(1, 1, 0) : VK_MAKE_VERSION(1, 0, 0);
+ vk::SpirvVersion spirv_version = cases[i].spv1p3 ? vk::SPIRV_VERSION_1_3 : vk::SPIRV_VERSION_1_0;
+ vk::SpirVAsmBuildOptions asm_options(vulkan_version, spirv_version);
+
+ const std::string file = std::string(cases[i].basename) + ".amber";
+ cts_amber::AmberTestCase *testCase = cts_amber::createAmberTestCase(testCtx,
+ cases[i].basename,
+ cases[i].description,
+ category.c_str(),
+ file);
+ DE_ASSERT(testCase != DE_NULL);
+ testCase->addRequirement("VK_KHR_shader_terminate_invocation");
+ const std::vector<std::string>& reqmts = cases[i].requirements;
+ for (size_t r = 0; r < reqmts.size() ; ++r)
+ {
+ testCase->addRequirement(reqmts[r]);
+ }
+
+ testCase->setSpirVAsmBuildOptions(asm_options);
+ tests->addChild(testCase);
+ }
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createTerminateInvocationGroup(tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> terminateTests(new tcu::TestCaseGroup(testCtx, "terminate_invocation", "VK_KHR_shader_terminate_invocation tests"));
+
+ const char* data_data = "spirv_assembly/instruction/terminate_invocation";
+
+ std::vector<std::string> Stores;
+ Stores.push_back("Features.fragmentStoresAndAtomics");
+
+ std::vector<std::string> VarPtr;
+ VarPtr.push_back("VariablePointerFeatures.variablePointersStorageBuffer");
+ VarPtr.push_back("Features.fragmentStoresAndAtomics");
+
+ std::vector<std::string> Vote;
+ Vote.push_back("SubgroupProperties.supportedOperations.vote");
+ Vote.push_back("SubgroupProperties.supportedStages.fragment");
+
+ std::vector<std::string> Ballot;
+ Ballot.push_back("SubgroupProperties.supportedOperations.ballot");
+ Ballot.push_back("SubgroupProperties.supportedStages.fragment");
+
+ CaseGroup group(data_data);
+ group.add("no_output_write", "no write to after calling terminate invocation", false);
+ group.add("no_output_write_before_terminate", "no write to output despite occurring before terminate invocation", false);
+ group.add("no_ssbo_store", "no store to SSBO when it occurs after terminate invocation", false, Stores);
+ group.add("no_ssbo_atomic", "no atomic update to SSBO when it occurs after terminate invocation", false, Stores);
+ group.add("ssbo_store_before_terminate", "ssbo store commits when it occurs before terminate invocation", false, Stores);
+ group.add("no_image_store", "no image write when it occurs after terminate invocation", false, Stores);
+ group.add("no_image_atomic", "no image atomic updates when it occurs after terminate invocation", false, Stores);
+ group.add("no_null_pointer_load", "null pointer should not be accessed by a load in a terminated invocation", false, VarPtr);
+ group.add("no_null_pointer_store", "null pointer should not be accessed by a store in a terminated invocation", false, VarPtr);
+ group.add("no_out_of_bounds_load", "out of bounds pointer should not be accessed by a load in a terminated invocation", false, VarPtr);
+ group.add("no_out_of_bounds_store", "out of bounds pointer should not be accessed by a store in a terminated invocation", false, VarPtr);
+ group.add("no_out_of_bounds_atomic", "out of bounds pointer should not be accessed by an atomic in a terminated invocation", false, VarPtr);
+ group.add("terminate_loop", "\"inifinite\" loop that calls terminate invocation", false);
+ group.add("subgroup_ballot", "checks that terminated invocations don't participate in the ballot", true, Ballot);
+ group.add("subgroup_vote", "checks that a subgroup all does not include any terminated invocations", true, Vote);
+ terminateTests->addChild(createTestGroup(testCtx, "terminate", "Terminate Invocation", addTestsForAmberFiles, group));
+
+ return terminateTests.release();
+}
+
+} // SpirVAssembly
+} // vkt
--- /dev/null
+#ifndef _VKTSPVASMTERMINATEINVOCATIONTESTS_HPP
+#define _VKTSPVASMTERMINATEINVOCATIONTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2020 Google LLC
+ * Copyright (c) 2020 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Test new features in VK_KHR_shader_terminate_invocation
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace SpirVAssembly
+{
+
+tcu::TestCaseGroup* createTerminateInvocationGroup (tcu::TestContext& testCtx);
+
+} // SpirVAssembly
+} // vkt
+
+#endif // _VKTSPVASMTERMINATEINVOCATIONTESTS_HPP
dEQP-VK.spirv_assembly.instruction.amd_trinary_minmax.mid3.f64.vec2
dEQP-VK.spirv_assembly.instruction.amd_trinary_minmax.mid3.f64.vec3
dEQP-VK.spirv_assembly.instruction.amd_trinary_minmax.mid3.f64.vec4
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_output_write
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_output_write_before_terminate
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_ssbo_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_ssbo_atomic
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.ssbo_store_before_terminate
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_image_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_image_atomic
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_null_pointer_load
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_null_pointer_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_out_of_bounds_load
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_out_of_bounds_store
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.no_out_of_bounds_atomic
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.terminate_loop
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.subgroup_ballot
+dEQP-VK.spirv_assembly.instruction.terminate_invocation.terminate.subgroup_vote
dEQP-VK.spirv_assembly.type.scalar.i8.negate_vert
dEQP-VK.spirv_assembly.type.scalar.i8.negate_tessc
dEQP-VK.spirv_assembly.type.scalar.i8.negate_tesse
VK_KHR_performance_query DEVICE
VK_KHR_shader_non_semantic_info DEVICE
VK_KHR_copy_commands2 DEVICE
+VK_KHR_shader_terminate_invocation DEVICE
VkPhysicalDeviceVulkan12Features FEATURES ( samplerFilterMinmax ) REQUIREMENTS ( "ApiVersion(1, 2, 0)" VK_EXT_sampler_filter_minmax )
VkPhysicalDeviceVulkan12Features FEATURES ( shaderOutputViewportIndex ) REQUIREMENTS ( "ApiVersion(1, 2, 0)" VK_EXT_shader_viewport_index_layer )
VkPhysicalDeviceVulkan12Features FEATURES ( shaderOutputLayer ) REQUIREMENTS ( "ApiVersion(1, 2, 0)" VK_EXT_shader_viewport_index_layer )
+VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR FEATURES ( shaderTerminateInvocation ) REQUIREMENTS ( VK_KHR_shader_terminate_invocation )