[27/35] arb_gl_spirv: add tests for atomic counter operations in CS

Submitted by apinheiro on Aug. 9, 2018, 11:36 a.m.

Details

Message ID 20180809113614.5122-28-apinheiro@igalia.com
State New
Headers show
Series "ARB_gl_spirv: all tests so far" ( rev: 1 ) in Piglit

Not browsing as part of any series.

Commit Message

apinheiro Aug. 9, 2018, 11:36 a.m.
From: Antia Puentes <apuentes@igalia.com>

Tests the atomic counter operations and layout qualifiers offset and binding
described in the ARB_shader_atomic_counters specification in a CS with
local_size_x, y, z equal to 3, 2 and 1 respectively.

Includes 3 tests: atomic_uint, arrays of atomic_uint and AOA of atomic_uints.
---
 .../uniform/atomic-uint-aoa-cs.shader_test         | 249 +++++++++++++++++++++
 .../uniform/atomic-uint-array-cs.shader_test       | 239 ++++++++++++++++++++
 .../execution/uniform/atomic-uint-cs.shader_test   | 244 ++++++++++++++++++++
 3 files changed, 732 insertions(+)
 create mode 100644 tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-aoa-cs.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-array-cs.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-cs.shader_test

Patch hide | download patch | download mbox

diff --git a/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-aoa-cs.shader_test b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-aoa-cs.shader_test
new file mode 100644
index 000000000..5bc3850bf
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-aoa-cs.shader_test
@@ -0,0 +1,249 @@ 
+# Tests the atomic counter operations described in the
+# ARB_shader_atomic_counters specification using AOAs
+# of atomic counters in a CS with  local_sizes_x, y, z
+# equal to 3, 2 and 1 respectively.
+#
+# Checks the final value of the atomic counter and the values
+# returned by the operations.
+#
+# The declaration of the atomic counters array uses the atomic
+# counter layout qualifiers binding and offset.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+
+[compute shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 6
+; Bound: 68
+; Schema: 0
+               OpCapability Shader
+               OpCapability AtomicStorage
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main" %gl_LocalInvocationIndex
+               OpExecutionMode %main LocalSize 3 2 1
+               OpSource GLSL 450
+               OpName %main "main"
+               OpName %a00_out "a00_out"
+               OpName %a "a"
+               OpName %a00_expected "a00_expected"
+               OpName %gl_LocalInvocationIndex "gl_LocalInvocationIndex"
+               OpName %ok_a00 "ok_a00"
+               OpName %a01_out "a01_out"
+               OpName %a01_expected "a01_expected"
+               OpName %ok_a01 "ok_a01"
+               OpName %a12_out "a12_out"
+               OpName %a12_expected "a12_expected"
+               OpName %ok_a12 "ok_a12"
+               OpDecorate %a Offset 4
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %a00_expected Location 0
+               OpDecorate %a00_expected DescriptorSet 0
+               OpDecorate %a00_expected Binding 4
+               OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+               OpDecorate %ok_a00 Offset 0
+               OpDecorate %ok_a00 DescriptorSet 0
+               OpDecorate %ok_a00 Binding 1
+               OpDecorate %a01_expected Location 6
+               OpDecorate %a01_expected DescriptorSet 0
+               OpDecorate %a01_expected Binding 5
+               OpDecorate %ok_a01 Offset 0
+               OpDecorate %ok_a01 DescriptorSet 0
+               OpDecorate %ok_a01 Binding 2
+               OpDecorate %a12_expected Location 12
+               OpDecorate %a12_expected DescriptorSet 0
+               OpDecorate %a12_expected Binding 6
+               OpDecorate %ok_a12 Offset 0
+               OpDecorate %ok_a12 DescriptorSet 0
+               OpDecorate %ok_a12 Binding 3
+               OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+%_ptr_Function_uint = OpTypePointer Function %uint
+     %uint_3 = OpConstant %uint 3
+%_arr_uint_uint_3 = OpTypeArray %uint %uint_3
+     %uint_2 = OpConstant %uint 2
+%_arr__arr_uint_uint_3_uint_2 = OpTypeArray %_arr_uint_uint_3 %uint_2
+%_ptr_AtomicCounter__arr__arr_uint_uint_3_uint_2 = OpTypePointer AtomicCounter %_arr__arr_uint_uint_3_uint_2
+          %a = OpVariable %_ptr_AtomicCounter__arr__arr_uint_uint_3_uint_2 AtomicCounter
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+%_ptr_AtomicCounter_uint = OpTypePointer AtomicCounter %uint
+     %uint_1 = OpConstant %uint 1
+     %uint_0 = OpConstant %uint 0
+     %uint_6 = OpConstant %uint 6
+%_arr_uint_uint_6 = OpTypeArray %uint %uint_6
+%_ptr_UniformConstant__arr_uint_uint_6 = OpTypePointer UniformConstant %_arr_uint_uint_6
+%a00_expected = OpVariable %_ptr_UniformConstant__arr_uint_uint_6 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%_ptr_UniformConstant_uint = OpTypePointer UniformConstant %uint
+       %bool = OpTypeBool
+     %ok_a00 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+      %int_1 = OpConstant %int 1
+%a01_expected = OpVariable %_ptr_UniformConstant__arr_uint_uint_6 UniformConstant
+     %ok_a01 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+      %int_2 = OpConstant %int 2
+%a12_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+     %ok_a12 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+     %v3uint = OpTypeVector %uint 3
+%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_3 %uint_2 %uint_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+    %a00_out = OpVariable %_ptr_Function_uint Function
+    %a01_out = OpVariable %_ptr_Function_uint Function
+    %a12_out = OpVariable %_ptr_Function_uint Function
+         %18 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_0 %int_0
+         %21 = OpAtomicIIncrement %uint %18 %uint_1 %uint_0
+               OpStore %a00_out %21
+         %22 = OpLoad %uint %a00_out
+         %29 = OpLoad %uint %gl_LocalInvocationIndex
+         %31 = OpAccessChain %_ptr_UniformConstant_uint %a00_expected %29
+         %32 = OpLoad %uint %31
+         %34 = OpIEqual %bool %22 %32
+               OpSelectionMerge %36 None
+               OpBranchConditional %34 %35 %36
+         %35 = OpLabel
+         %38 = OpAtomicIIncrement %uint %ok_a00 %uint_1 %uint_0
+               OpBranch %36
+         %36 = OpLabel
+         %41 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_0 %int_1
+         %42 = OpAtomicIDecrement %uint %41 %uint_1 %uint_0
+         %43 = OpISub %uint %42 %int_1
+               OpStore %a01_out %43
+         %44 = OpLoad %uint %a01_out
+         %46 = OpLoad %uint %gl_LocalInvocationIndex
+         %47 = OpAccessChain %_ptr_UniformConstant_uint %a01_expected %46
+         %48 = OpLoad %uint %47
+         %49 = OpIEqual %bool %44 %48
+               OpSelectionMerge %51 None
+               OpBranchConditional %49 %50 %51
+         %50 = OpLabel
+         %53 = OpAtomicIIncrement %uint %ok_a01 %uint_1 %uint_0
+               OpBranch %51
+         %51 = OpLabel
+         %56 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_1 %int_2
+         %57 = OpAtomicLoad %uint %56 %uint_1 %uint_0
+               OpStore %a12_out %57
+         %58 = OpLoad %uint %a12_out
+         %60 = OpLoad %uint %a12_expected
+         %61 = OpIEqual %bool %58 %60
+               OpSelectionMerge %63 None
+               OpBranchConditional %61 %62 %63
+         %62 = OpLabel
+         %65 = OpAtomicIIncrement %uint %ok_a12 %uint_1 %uint_0
+               OpBranch %63
+         %63 = OpLabel
+               OpReturn
+               OpFunctionEnd
+
+[compute shader]
+#version 450
+
+layout (local_size_x = 3, local_size_y = 2, local_size_z = 1) in;
+
+layout (binding = 0, offset = 4) uniform atomic_uint a[2][3];
+
+layout (binding = 1) uniform atomic_uint ok_a00;
+layout (binding = 2) uniform atomic_uint ok_a01;
+layout (binding = 3) uniform atomic_uint ok_a12;
+
+layout (location = 0) uniform uint a00_expected[6];
+layout (location = 6) uniform uint a01_expected[6];
+layout (location = 12) uniform uint a12_expected;
+
+void main()
+{
+    uint a00_out = atomicCounterIncrement(a[0][0]);
+    if (a00_out == a00_expected[gl_LocalInvocationIndex])
+       atomicCounterIncrement(ok_a00);
+
+    uint a01_out = atomicCounterDecrement(a[0][1]);
+    if (a01_out == a01_expected[gl_LocalInvocationIndex])
+       atomicCounterIncrement(ok_a01);
+
+    uint a12_out = atomicCounter(a[1][2]);
+    if (a12_out == a12_expected)
+       atomicCounterIncrement(ok_a12);
+}
+
+[test]
+
+# Initialize atomic counters
+
+atomic counter buffer 0 7
+
+atomic counter buffer 1 1
+atomic counter buffer 2 1
+atomic counter buffer 3 1
+
+atomic counter 0 0 0
+
+atomic counter 0 1 10  # a[0][0]
+atomic counter 0 2 20  # a[0][1]
+atomic counter 0 3 0   # a[0][2]
+atomic counter 0 4 0   # a[1][0]
+atomic counter 0 5 0   # a[1][1]
+atomic counter 0 6 30  # a[1][2]
+
+atomic counter 1 0 0   # ok_a00
+atomic counter 2 0 0   # ok_a01
+atomic counter 3 0 0   # ok_a12
+
+# Expected return values for the atomic counter operations
+# depending on the invocation number.
+
+uniform uint 0 10  # a00_expected[0]
+uniform uint 1 11  # a00_expected[1]
+uniform uint 2 12  # a00_expected[2]
+uniform uint 3 13  # a00_expected[3]
+uniform uint 4 14  # a00_expected[4]
+uniform uint 5 15  # a00_expected[5]
+
+uniform uint 6 19   # a01_expected[0]
+uniform uint 7 18   # a01_expected[1]
+uniform uint 8 17   # a01_expected[2]
+uniform uint 9 16   # a01_expected[3]
+uniform uint 10 15  # a01_expected[4]
+uniform uint 11 14  # a01_expected[5]
+
+uniform uint 12 30  # a12_expected
+
+# Check original values for the atomic counters
+
+probe atomic counter buffer 0 0 == 0
+
+probe atomic counter buffer 0 4 == 10   # a[0][0]
+probe atomic counter buffer 0 8 == 20   # a[0][1]
+probe atomic counter buffer 0 12 == 0   # a[0][2]
+probe atomic counter buffer 0 16 == 0   # a[1][0]
+probe atomic counter buffer 0 20 == 0   # a[1][1]
+probe atomic counter buffer 0 24 == 30  # a[1][2]
+
+probe atomic counter buffer 1 0 == 0   # ok_a00
+probe atomic counter buffer 2 0 == 0   # ok_a01
+probe atomic counter buffer 3 0 == 0   # ok_a12
+
+compute 1 1 1
+
+# Check final values for the atomic counters
+
+probe atomic counter buffer 0 0 == 0
+
+probe atomic counter buffer 0 4 == 16   # a[0][0]
+probe atomic counter buffer 0 8 == 14   # a[0][1]
+probe atomic counter buffer 0 12 == 0   # a[0][2]
+probe atomic counter buffer 0 16 == 0   # a[1][0]
+probe atomic counter buffer 0 20 == 0   # a[1][1]
+probe atomic counter buffer 0 24 == 30  # a[1][2]
+
+probe atomic counter buffer 1 0 == 6   # ok_a00
+probe atomic counter buffer 2 0 == 6   # ok_a01
+probe atomic counter buffer 3 0 == 6   # ok_a12
diff --git a/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-array-cs.shader_test b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-array-cs.shader_test
new file mode 100644
index 000000000..a9f831dbd
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-array-cs.shader_test
@@ -0,0 +1,239 @@ 
+# Tests the atomic counter operations described in the
+# ARB_shader_atomic_counters specification using arrays
+# of atomic counters in a CS with  local_sizes_x, y, z
+# equal to 3, 2 and 1 respectively.
+#
+# Checks the final value of the atomic counter and the values
+# returned by the operations.
+#
+# The declaration of the atomic counters array uses the atomic
+# counter layout qualifiers binding and offset.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+
+[compute shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 6
+; Bound: 67
+; Schema: 0
+               OpCapability Shader
+               OpCapability AtomicStorage
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main" %gl_LocalInvocationIndex
+               OpExecutionMode %main LocalSize 3 2 1
+               OpSource GLSL 450
+               OpName %main "main"
+               OpName %a0_out "a0_out"
+               OpName %a "a"
+               OpName %a0_expected "a0_expected"
+               OpName %gl_LocalInvocationIndex "gl_LocalInvocationIndex"
+               OpName %ok_a0 "ok_a0"
+               OpName %a1_out "a1_out"
+               OpName %a1_expected "a1_expected"
+               OpName %ok_a1 "ok_a1"
+               OpName %a2_out "a2_out"
+               OpName %a2_expected "a2_expected"
+               OpName %ok_a2 "ok_a2"
+               OpDecorate %a Offset 4
+               OpDecorate %a DescriptorSet 0
+               OpDecorate %a Binding 0
+               OpDecorate %a0_expected Location 0
+               OpDecorate %a0_expected DescriptorSet 0
+               OpDecorate %a0_expected Binding 4
+               OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+               OpDecorate %ok_a0 Offset 0
+               OpDecorate %ok_a0 DescriptorSet 0
+               OpDecorate %ok_a0 Binding 1
+               OpDecorate %a1_expected Location 6
+               OpDecorate %a1_expected DescriptorSet 0
+               OpDecorate %a1_expected Binding 5
+               OpDecorate %ok_a1 Offset 0
+               OpDecorate %ok_a1 DescriptorSet 0
+               OpDecorate %ok_a1 Binding 2
+               OpDecorate %a2_expected Location 12
+               OpDecorate %a2_expected DescriptorSet 0
+               OpDecorate %a2_expected Binding 6
+               OpDecorate %ok_a2 Offset 0
+               OpDecorate %ok_a2 DescriptorSet 0
+               OpDecorate %ok_a2 Binding 3
+               OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+%_ptr_Function_uint = OpTypePointer Function %uint
+     %uint_3 = OpConstant %uint 3
+%_arr_uint_uint_3 = OpTypeArray %uint %uint_3
+%_ptr_AtomicCounter__arr_uint_uint_3 = OpTypePointer AtomicCounter %_arr_uint_uint_3
+          %a = OpVariable %_ptr_AtomicCounter__arr_uint_uint_3 AtomicCounter
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+%_ptr_AtomicCounter_uint = OpTypePointer AtomicCounter %uint
+     %uint_1 = OpConstant %uint 1
+     %uint_0 = OpConstant %uint 0
+     %uint_6 = OpConstant %uint 6
+%_arr_uint_uint_6 = OpTypeArray %uint %uint_6
+%_ptr_UniformConstant__arr_uint_uint_6 = OpTypePointer UniformConstant %_arr_uint_uint_6
+%a0_expected = OpVariable %_ptr_UniformConstant__arr_uint_uint_6 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%_ptr_UniformConstant_uint = OpTypePointer UniformConstant %uint
+       %bool = OpTypeBool
+      %ok_a0 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+      %int_1 = OpConstant %int 1
+%a1_expected = OpVariable %_ptr_UniformConstant__arr_uint_uint_6 UniformConstant
+      %ok_a1 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+      %int_2 = OpConstant %int 2
+%a2_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+      %ok_a2 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+     %v3uint = OpTypeVector %uint 3
+     %uint_2 = OpConstant %uint 2
+%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_3 %uint_2 %uint_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+     %a0_out = OpVariable %_ptr_Function_uint Function
+     %a1_out = OpVariable %_ptr_Function_uint Function
+     %a2_out = OpVariable %_ptr_Function_uint Function
+         %16 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_0
+         %19 = OpAtomicIIncrement %uint %16 %uint_1 %uint_0
+               OpStore %a0_out %19
+         %20 = OpLoad %uint %a0_out
+         %27 = OpLoad %uint %gl_LocalInvocationIndex
+         %29 = OpAccessChain %_ptr_UniformConstant_uint %a0_expected %27
+         %30 = OpLoad %uint %29
+         %32 = OpIEqual %bool %20 %30
+               OpSelectionMerge %34 None
+               OpBranchConditional %32 %33 %34
+         %33 = OpLabel
+         %36 = OpAtomicIIncrement %uint %ok_a0 %uint_1 %uint_0
+               OpBranch %34
+         %34 = OpLabel
+         %39 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_1
+         %40 = OpAtomicIDecrement %uint %39 %uint_1 %uint_0
+         %41 = OpISub %uint %40 %int_1
+               OpStore %a1_out %41
+         %42 = OpLoad %uint %a1_out
+         %44 = OpLoad %uint %gl_LocalInvocationIndex
+         %45 = OpAccessChain %_ptr_UniformConstant_uint %a1_expected %44
+         %46 = OpLoad %uint %45
+         %47 = OpIEqual %bool %42 %46
+               OpSelectionMerge %49 None
+               OpBranchConditional %47 %48 %49
+         %48 = OpLabel
+         %51 = OpAtomicIIncrement %uint %ok_a1 %uint_1 %uint_0
+               OpBranch %49
+         %49 = OpLabel
+         %54 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_2
+         %55 = OpAtomicLoad %uint %54 %uint_1 %uint_0
+               OpStore %a2_out %55
+         %56 = OpLoad %uint %a2_out
+         %58 = OpLoad %uint %a2_expected
+         %59 = OpIEqual %bool %56 %58
+               OpSelectionMerge %61 None
+               OpBranchConditional %59 %60 %61
+         %60 = OpLabel
+         %63 = OpAtomicIIncrement %uint %ok_a2 %uint_1 %uint_0
+               OpBranch %61
+         %61 = OpLabel
+               OpReturn
+               OpFunctionEnd
+
+[compute shader]
+#version 450
+
+layout (local_size_x = 3, local_size_y = 2, local_size_z = 1) in;
+
+layout (binding = 0, offset = 4) uniform atomic_uint a[3];
+
+layout (binding = 1) uniform atomic_uint ok_a0;
+layout (binding = 2) uniform atomic_uint ok_a1;
+layout (binding = 3) uniform atomic_uint ok_a2;
+
+layout (location = 0) uniform uint a0_expected[6];
+layout (location = 6) uniform uint a1_expected[6];
+layout (location = 12) uniform uint a2_expected;
+
+void main()
+{
+    uint a0_out = atomicCounterIncrement(a[0]);
+    if (a0_out == a0_expected[gl_LocalInvocationIndex])
+       atomicCounterIncrement(ok_a0);
+
+    uint a1_out = atomicCounterDecrement(a[1]);
+    if (a1_out == a1_expected[gl_LocalInvocationIndex])
+       atomicCounterIncrement(ok_a1);
+
+    uint a2_out = atomicCounter(a[2]);
+    if (a2_out == a2_expected)
+       atomicCounterIncrement(ok_a2);
+}
+
+[test]
+
+# Initialize atomic counters
+
+atomic counter buffer 0 4
+
+atomic counter buffer 1 1
+atomic counter buffer 2 1
+atomic counter buffer 3 1
+
+atomic counter 0 0 0
+
+atomic counter 0 1 10  # a[0]
+atomic counter 0 2 20  # a[1]
+atomic counter 0 3 30  # a[2]
+
+atomic counter 1 0 0   # ok_a0
+atomic counter 2 0 0   # ok_a1
+atomic counter 3 0 0   # ok_a2
+
+# Expected return values for the atomic counter operations
+# depending on the invocation number.
+
+uniform uint 0 10  # a0_expected[0]
+uniform uint 1 11  # a0_expected[1]
+uniform uint 2 12  # a0_expected[2]
+uniform uint 3 13  # a0_expected[3]
+uniform uint 4 14  # a0_expected[4]
+uniform uint 5 15  # a0_expected[5]
+
+uniform uint 6 19   # a1_expected[0]
+uniform uint 7 18   # a1_expected[1]
+uniform uint 8 17   # a1_expected[2]
+uniform uint 9 16   # a1_expected[3]
+uniform uint 10 15  # a1_expected[4]
+uniform uint 11 14  # a1_expected[5]
+
+uniform uint 12 30  # a2_expected
+
+# Check original values for the atomic counters
+
+probe atomic counter buffer 0 0 == 0
+
+probe atomic counter buffer 0 4 == 10  # a[0]
+probe atomic counter buffer 0 8 == 20  # a[1]
+probe atomic counter buffer 0 12 == 30 # a[2]
+
+probe atomic counter buffer 1 0 == 0   # ok_a0
+probe atomic counter buffer 2 0 == 0   # ok_b0
+probe atomic counter buffer 3 0 == 0   # ok_c0
+
+compute 1 1 1
+
+# Check final values for the atomic counters
+
+probe atomic counter buffer 0 0 == 0
+
+probe atomic counter buffer 0 4 == 16  # a[0]
+probe atomic counter buffer 0 8 == 14  # a[1]
+probe atomic counter buffer 0 12 == 30 # a[2]
+
+probe atomic counter buffer 1 0 == 6   # ok_a0
+probe atomic counter buffer 2 0 == 6   # ok_a1
+probe atomic counter buffer 3 0 == 6   # ok_a2
diff --git a/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-cs.shader_test b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-cs.shader_test
new file mode 100644
index 000000000..ad2896a8a
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-cs.shader_test
@@ -0,0 +1,244 @@ 
+# Tests the atomic counter operations described in the
+# ARB_shader_atomic_counters specification in a CS with
+# local_sizes_x, y, z equal to 3, 2 and 1 respectively.
+#
+# Checks the final value of the atomic counter and the values
+# returned by the operations.
+#
+# The declaration of the atomic counters uses the atomic counter
+# layout qualifiers binding and offset.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+
+[compute shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 6
+; Bound: 62
+; Schema: 0
+               OpCapability Shader
+               OpCapability AtomicStorage
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main" %gl_LocalInvocationIndex
+               OpExecutionMode %main LocalSize 3 2 1
+               OpSource GLSL 450
+               OpName %main "main"
+               OpName %a0_out "a0_out"
+               OpName %a0 "a0"
+               OpName %a0_expected "a0_expected"
+               OpName %gl_LocalInvocationIndex "gl_LocalInvocationIndex"
+               OpName %ok_a0 "ok_a0"
+               OpName %b0_out "b0_out"
+               OpName %b0 "b0"
+               OpName %b0_expected "b0_expected"
+               OpName %ok_b0 "ok_b0"
+               OpName %c0_out "c0_out"
+               OpName %c0 "c0"
+               OpName %c0_expected "c0_expected"
+               OpName %ok_c0 "ok_c0"
+               OpDecorate %a0 Offset 24
+               OpDecorate %a0 DescriptorSet 0
+               OpDecorate %a0 Binding 3
+               OpDecorate %a0_expected Location 0
+               OpDecorate %a0_expected DescriptorSet 0
+               OpDecorate %a0_expected Binding 0
+               OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+               OpDecorate %ok_a0 Offset 0
+               OpDecorate %ok_a0 DescriptorSet 0
+               OpDecorate %ok_a0 Binding 4
+               OpDecorate %b0 Offset 0
+               OpDecorate %b0 DescriptorSet 0
+               OpDecorate %b0 Binding 2
+               OpDecorate %b0_expected Location 6
+               OpDecorate %b0_expected DescriptorSet 0
+               OpDecorate %b0_expected Binding 7
+               OpDecorate %ok_b0 Offset 0
+               OpDecorate %ok_b0 DescriptorSet 0
+               OpDecorate %ok_b0 Binding 5
+               OpDecorate %c0 Offset 4
+               OpDecorate %c0 DescriptorSet 0
+               OpDecorate %c0 Binding 1
+               OpDecorate %c0_expected Location 12
+               OpDecorate %c0_expected DescriptorSet 0
+               OpDecorate %c0_expected Binding 8
+               OpDecorate %ok_c0 Offset 0
+               OpDecorate %ok_c0 DescriptorSet 0
+               OpDecorate %ok_c0 Binding 6
+               OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+%_ptr_Function_uint = OpTypePointer Function %uint
+%_ptr_AtomicCounter_uint = OpTypePointer AtomicCounter %uint
+         %a0 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+     %uint_1 = OpConstant %uint 1
+     %uint_0 = OpConstant %uint 0
+     %uint_6 = OpConstant %uint 6
+%_arr_uint_uint_6 = OpTypeArray %uint %uint_6
+%_ptr_UniformConstant__arr_uint_uint_6 = OpTypePointer UniformConstant %_arr_uint_uint_6
+%a0_expected = OpVariable %_ptr_UniformConstant__arr_uint_uint_6 UniformConstant
+%_ptr_Input_uint = OpTypePointer Input %uint
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%_ptr_UniformConstant_uint = OpTypePointer UniformConstant %uint
+       %bool = OpTypeBool
+      %ok_a0 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+         %b0 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%b0_expected = OpVariable %_ptr_UniformConstant__arr_uint_uint_6 UniformConstant
+      %ok_b0 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+         %c0 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+%c0_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+      %ok_c0 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+     %v3uint = OpTypeVector %uint 3
+     %uint_3 = OpConstant %uint 3
+     %uint_2 = OpConstant %uint 2
+%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_3 %uint_2 %uint_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+     %a0_out = OpVariable %_ptr_Function_uint Function
+     %b0_out = OpVariable %_ptr_Function_uint Function
+     %c0_out = OpVariable %_ptr_Function_uint Function
+         %13 = OpAtomicIIncrement %uint %a0 %uint_1 %uint_0
+               OpStore %a0_out %13
+         %14 = OpLoad %uint %a0_out
+         %21 = OpLoad %uint %gl_LocalInvocationIndex
+         %23 = OpAccessChain %_ptr_UniformConstant_uint %a0_expected %21
+         %24 = OpLoad %uint %23
+         %26 = OpIEqual %bool %14 %24
+               OpSelectionMerge %28 None
+               OpBranchConditional %26 %27 %28
+         %27 = OpLabel
+         %30 = OpAtomicIIncrement %uint %ok_a0 %uint_1 %uint_0
+               OpBranch %28
+         %28 = OpLabel
+         %33 = OpAtomicIDecrement %uint %b0 %uint_1 %uint_0
+         %36 = OpISub %uint %33 %int_1
+               OpStore %b0_out %36
+         %37 = OpLoad %uint %b0_out
+         %39 = OpLoad %uint %gl_LocalInvocationIndex
+         %40 = OpAccessChain %_ptr_UniformConstant_uint %b0_expected %39
+         %41 = OpLoad %uint %40
+         %42 = OpIEqual %bool %37 %41
+               OpSelectionMerge %44 None
+               OpBranchConditional %42 %43 %44
+         %43 = OpLabel
+         %46 = OpAtomicIIncrement %uint %ok_b0 %uint_1 %uint_0
+               OpBranch %44
+         %44 = OpLabel
+         %49 = OpAtomicLoad %uint %c0 %uint_1 %uint_0
+               OpStore %c0_out %49
+         %50 = OpLoad %uint %c0_out
+         %52 = OpLoad %uint %c0_expected
+         %53 = OpIEqual %bool %50 %52
+               OpSelectionMerge %55 None
+               OpBranchConditional %53 %54 %55
+         %54 = OpLabel
+         %57 = OpAtomicIIncrement %uint %ok_c0 %uint_1 %uint_0
+               OpBranch %55
+         %55 = OpLabel
+               OpReturn
+               OpFunctionEnd
+
+[compute shader]
+#version 450
+
+layout (local_size_x = 3, local_size_y = 2, local_size_z = 1) in;
+
+layout (binding = 3, offset = 24) uniform atomic_uint a0;
+layout (binding = 2) uniform atomic_uint b0;
+layout (binding = 1, offset = 4) uniform atomic_uint c0;
+
+layout (binding = 4) uniform atomic_uint ok_a0;
+layout (binding = 5) uniform atomic_uint ok_b0;
+layout (binding = 6) uniform atomic_uint ok_c0;
+
+layout (location = 0) uniform uint a0_expected[6];
+layout (location = 6) uniform uint b0_expected[6];
+layout (location = 12) uniform uint c0_expected;
+
+void main()
+{
+    uint a0_out = atomicCounterIncrement(a0);
+    if (a0_out == a0_expected[gl_LocalInvocationIndex])
+       atomicCounterIncrement(ok_a0);
+
+    uint b0_out = atomicCounterDecrement(b0);
+    if (b0_out == b0_expected[gl_LocalInvocationIndex])
+       atomicCounterIncrement(ok_b0);
+
+    uint c0_out = atomicCounter(c0);
+    if (c0_out == c0_expected)
+       atomicCounterIncrement(ok_c0);
+}
+
+[test]
+
+# Initialize atomic counters
+
+atomic counter buffer 3 7
+atomic counter buffer 2 1
+atomic counter buffer 1 2
+
+atomic counter buffer 4 1
+atomic counter buffer 5 1
+atomic counter buffer 6 1
+
+atomic counter 3 5 0
+atomic counter 3 6 5   # a0
+atomic counter 2 0 10  # b0
+atomic counter 1 1 7   # c0
+
+atomic counter 4 0 0   # ok_a0
+atomic counter 5 0 0   # ok_b0
+atomic counter 6 0 0   # ok_c0
+
+# Expected return values for the atomic counter operations
+# depending on the invocation number.
+
+uniform uint 0 5   # a0_expected[0]
+uniform uint 1 6   # a0_expected[1]
+uniform uint 2 7   # a0_expected[2]
+uniform uint 3 8   # a0_expected[3]
+uniform uint 4 9   # a0_expected[4]
+uniform uint 5 10  # a0_expected[5]
+
+uniform uint 6 9   # b0_expected[0]
+uniform uint 7 8   # b0_expected[1]
+uniform uint 8 7   # b0_expected[2]
+uniform uint 9 6   # b0_expected[3]
+uniform uint 10 5  # b0_expected[4]
+uniform uint 11 4  # b0_expected[5]
+
+uniform uint 12 7  # c0_expected
+
+# Check original values for the atomic counters
+
+probe atomic counter buffer 3 20 == 0
+
+probe atomic counter buffer 3 24 == 5  # a0
+probe atomic counter buffer 2 0 == 10  # b0
+probe atomic counter buffer 1 4 == 7   # c0
+
+probe atomic counter buffer 4 0 == 0   # ok_a0
+probe atomic counter buffer 5 0 == 0   # ok_b0
+probe atomic counter buffer 6 0 == 0   # ok_c0
+
+compute 1 1 1
+
+# Check final values for the atomic counters
+
+probe atomic counter buffer 3 20 == 0
+
+probe atomic counter buffer 3 24 == 11 # a0
+probe atomic counter buffer 2 0 == 4   # b0
+probe atomic counter buffer 1 4 == 7   # c0
+
+probe atomic counter buffer 4 0 == 6   # ok_a0
+probe atomic counter buffer 5 0 == 6   # ok_b0
+probe atomic counter buffer 6 0 == 6   # ok_c0