[26/35] arb_gl_spirv: add tests for atomic counter operations in FS

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

Details

Message ID 20180809113614.5122-27-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.

They check the final values for the atomic counters and that the values returned
by the atomic counter operations are the expected ones.

Includes 3 tests: atomic_uint, arrays of atomic_uint and AOA of atomic_uints.
---
 .../uniform/atomic-uint-aoa-fs.shader_test         | 222 +++++++++++++++++++++
 .../uniform/atomic-uint-array-fs.shader_test       | 211 ++++++++++++++++++++
 .../execution/uniform/atomic-uint-fs.shader_runner | 219 ++++++++++++++++++++
 3 files changed, 652 insertions(+)
 create mode 100644 tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-aoa-fs.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-array-fs.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-fs.shader_runner

Patch hide | download patch | download mbox

diff --git a/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-aoa-fs.shader_test b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-aoa-fs.shader_test
new file mode 100644
index 000000000..f259d3c0f
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-aoa-fs.shader_test
@@ -0,0 +1,222 @@ 
+# Tests the atomic counter operations described in the
+# ARB_shader_atomic_counters spec for an array of arrays of
+# atomic counters in a fragment shader.
+#
+# Checks the final value of the atomic counters and the values
+# returned by the operations.
+#
+# The declaration of the atomic counter AOA uses the atomic counter
+# layout qualifiers binding and offset.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+
+[vertex shader passthrough]
+
+[fragment 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: 76
+; Schema: 0
+               OpCapability Shader
+               OpCapability AtomicStorage
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %color
+               OpExecutionMode %main OriginLowerLeft
+               OpSource GLSL 450
+               OpName %main "main"
+               OpName %a0_out "a0_out"
+               OpName %a "a"
+               OpName %a0_expected "a0_expected"
+               OpName %color "color"
+               OpName %a1_out "a1_out"
+               OpName %a1_expected "a1_expected"
+               OpName %a2_out "a2_out"
+               OpName %a2_expected "a2_expected"
+               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 1
+               OpDecorate %color Location 0
+               OpDecorate %a1_expected Location 1
+               OpDecorate %a1_expected DescriptorSet 0
+               OpDecorate %a1_expected Binding 2
+               OpDecorate %a2_expected Location 2
+               OpDecorate %a2_expected DescriptorSet 0
+               OpDecorate %a2_expected Binding 3
+       %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
+%_ptr_UniformConstant_uint = OpTypePointer UniformConstant %uint
+%a0_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+       %bool = OpTypeBool
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_1 = OpConstant %float 1
+    %float_0 = OpConstant %float 0
+  %float_255 = OpConstant %float 255
+      %int_1 = OpConstant %int 1
+%a1_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+%float_0_100000001 = OpConstant %float 0.100000001
+      %int_2 = OpConstant %int 2
+%a2_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+%float_0_200000003 = OpConstant %float 0.200000003
+         %75 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_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
+         %18 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_0 %int_0
+         %21 = OpAtomicLoad %uint %18 %uint_1 %uint_0
+               OpStore %a0_out %21
+         %22 = OpLoad %uint %a0_out
+         %25 = OpLoad %uint %a0_expected
+         %27 = OpINotEqual %bool %22 %25
+               OpSelectionMerge %29 None
+               OpBranchConditional %27 %28 %29
+         %28 = OpLabel
+         %36 = OpLoad %uint %a0_out
+         %37 = OpConvertUToF %float %36
+         %39 = OpFDiv %float %37 %float_255
+         %40 = OpCompositeConstruct %v4float %float_1 %float_0 %39 %float_1
+               OpStore %color %40
+               OpReturn
+         %29 = OpLabel
+         %44 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_1 %int_1
+         %45 = OpAtomicIIncrement %uint %44 %uint_1 %uint_0
+               OpStore %a1_out %45
+         %46 = OpLoad %uint %a1_out
+         %48 = OpLoad %uint %a1_expected
+         %49 = OpINotEqual %bool %46 %48
+               OpSelectionMerge %51 None
+               OpBranchConditional %49 %50 %51
+         %50 = OpLabel
+         %53 = OpLoad %uint %a1_out
+         %54 = OpConvertUToF %float %53
+         %55 = OpFDiv %float %54 %float_255
+         %56 = OpCompositeConstruct %v4float %float_1 %float_0_100000001 %55 %float_1
+               OpStore %color %56
+               OpReturn
+         %51 = OpLabel
+         %60 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_1 %int_2
+         %61 = OpAtomicIDecrement %uint %60 %uint_1 %uint_0
+         %62 = OpISub %uint %61 %int_1
+               OpStore %a2_out %62
+         %63 = OpLoad %uint %a2_out
+         %65 = OpLoad %uint %a2_expected
+         %66 = OpINotEqual %bool %63 %65
+               OpSelectionMerge %68 None
+               OpBranchConditional %66 %67 %68
+         %67 = OpLabel
+         %70 = OpLoad %uint %a2_out
+         %71 = OpConvertUToF %float %70
+         %72 = OpFDiv %float %71 %float_255
+         %73 = OpCompositeConstruct %v4float %float_1 %float_0_200000003 %72 %float_1
+               OpStore %color %73
+               OpReturn
+         %68 = OpLabel
+               OpStore %color %75
+               OpReturn
+               OpFunctionEnd
+
+[fragment shader]
+#version 450
+
+layout (binding = 0, offset = 4) uniform atomic_uint a[2][3];
+
+layout (location = 0) uniform uint a0_expected;
+layout (location = 1) uniform uint a1_expected;
+layout (location = 2) uniform uint a2_expected;
+
+layout (location = 0) out vec4 color;
+
+void main()
+{
+	uint a0_out = atomicCounter(a[0][0]);
+	if (a0_out != a0_expected) {
+		color = vec4(1.0, 0.0, float(a0_out) / 255.0, 1.0);
+		return;
+	}
+
+	uint a1_out = atomicCounterIncrement(a[1][1]);
+	if (a1_out != a1_expected) {
+		color = vec4(1.0, 0.1, float(a1_out) / 255.0, 1.0);
+		return;
+	}
+
+	uint a2_out = atomicCounterDecrement(a[1][2]);
+	if (a2_out != a2_expected) {
+		color = vec4(1.0, 0.2, float(a2_out) / 255.0, 1.0);
+		return;
+	}
+
+	color = vec4(0.0, 1.0, 0.0, 1.0);
+}
+
+[test]
+
+clear color 0.0 0.0 0.0 0.0
+clear
+
+# Initialize atomic counters
+
+atomic counter buffer 0 7
+atomic counter 0 0 0
+atomic counter 0 1 3
+atomic counter 0 2 6
+atomic counter 0 3 9
+atomic counter 0 4 12
+atomic counter 0 5 15
+atomic counter 0 6 18
+
+# Expected return values for the atomic counter operations
+
+uniform uint 0 3
+uniform uint 1 15
+uniform uint 2 17
+
+# Check original values for the atomic counters
+
+probe atomic counter buffer 0 0 == 0   # outside array (offset qualifier was 4)
+probe atomic counter buffer 0 4 == 3   # a[0][0]
+probe atomic counter buffer 0 8 == 6   # a[0][1]
+probe atomic counter buffer 0 12 == 9  # a[0][2]
+probe atomic counter buffer 0 16 == 12 # a[1][0]
+probe atomic counter buffer 0 20 == 15 # a[1][1]
+probe atomic counter buffer 0 24 == 18 # a[1][2]
+
+draw rect ortho 0 0 1 1
+
+# Check final values for the atomic counters
+
+probe atomic counter buffer 0 0 == 0    # outside array (offset qualifier was 4)
+probe atomic counter buffer 0 4 == 3    # a[0][0]
+probe atomic counter buffer 0 8 == 6    # a[0][1]
+probe atomic counter buffer 0 12 == 9   # a[0][2]
+probe atomic counter buffer 0 16 == 12  # a[1][0]
+probe atomic counter buffer 0 20 == 16  # a[1][1]
+probe atomic counter buffer 0 24 == 17  # a[1][2]
+
+probe rgba 0 0 0.0 1.0 0.0 1.0
diff --git a/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-array-fs.shader_test b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-array-fs.shader_test
new file mode 100644
index 000000000..444d0aaa9
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-array-fs.shader_test
@@ -0,0 +1,211 @@ 
+# Tests the atomic counter operations described in the
+# ARB_shader_atomic_counters spec for an array of atomic
+# counters in a FS.
+#
+# Checks the final value of the atomic counters and the
+# values returned by the operations.
+#
+# The declaration of the atomic counter array uses the atomic
+# counter layout qualifiers binding and offset.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+
+[vertex shader passthrough]
+
+[fragment 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: 74
+; Schema: 0
+               OpCapability Shader
+               OpCapability AtomicStorage
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %color
+               OpExecutionMode %main OriginLowerLeft
+               OpSource GLSL 450
+               OpName %main "main"
+               OpName %a0_out "a0_out"
+               OpName %a "a"
+               OpName %a0_expected "a0_expected"
+               OpName %color "color"
+               OpName %a1_out "a1_out"
+               OpName %a1_expected "a1_expected"
+               OpName %a2_out "a2_out"
+               OpName %a2_expected "a2_expected"
+               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 1
+               OpDecorate %color Location 0
+               OpDecorate %a1_expected Location 1
+               OpDecorate %a1_expected DescriptorSet 0
+               OpDecorate %a1_expected Binding 2
+               OpDecorate %a2_expected Location 2
+               OpDecorate %a2_expected DescriptorSet 0
+               OpDecorate %a2_expected Binding 3
+       %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
+%_ptr_UniformConstant_uint = OpTypePointer UniformConstant %uint
+%a0_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+       %bool = OpTypeBool
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_1 = OpConstant %float 1
+    %float_0 = OpConstant %float 0
+  %float_255 = OpConstant %float 255
+      %int_1 = OpConstant %int 1
+%a1_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+%float_0_100000001 = OpConstant %float 0.100000001
+      %int_2 = OpConstant %int 2
+%a2_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+%float_0_200000003 = OpConstant %float 0.200000003
+         %73 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_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 = OpAtomicLoad %uint %16 %uint_1 %uint_0
+               OpStore %a0_out %19
+         %20 = OpLoad %uint %a0_out
+         %23 = OpLoad %uint %a0_expected
+         %25 = OpINotEqual %bool %20 %23
+               OpSelectionMerge %27 None
+               OpBranchConditional %25 %26 %27
+         %26 = OpLabel
+         %34 = OpLoad %uint %a0_out
+         %35 = OpConvertUToF %float %34
+         %37 = OpFDiv %float %35 %float_255
+         %38 = OpCompositeConstruct %v4float %float_1 %float_0 %37 %float_1
+               OpStore %color %38
+               OpReturn
+         %27 = OpLabel
+         %42 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_1
+         %43 = OpAtomicIIncrement %uint %42 %uint_1 %uint_0
+               OpStore %a1_out %43
+         %44 = OpLoad %uint %a1_out
+         %46 = OpLoad %uint %a1_expected
+         %47 = OpINotEqual %bool %44 %46
+               OpSelectionMerge %49 None
+               OpBranchConditional %47 %48 %49
+         %48 = OpLabel
+         %51 = OpLoad %uint %a1_out
+         %52 = OpConvertUToF %float %51
+         %53 = OpFDiv %float %52 %float_255
+         %54 = OpCompositeConstruct %v4float %float_1 %float_0_100000001 %53 %float_1
+               OpStore %color %54
+               OpReturn
+         %49 = OpLabel
+         %58 = OpAccessChain %_ptr_AtomicCounter_uint %a %int_2
+         %59 = OpAtomicIDecrement %uint %58 %uint_1 %uint_0
+         %60 = OpISub %uint %59 %int_1
+               OpStore %a2_out %60
+         %61 = OpLoad %uint %a2_out
+         %63 = OpLoad %uint %a2_expected
+         %64 = OpINotEqual %bool %61 %63
+               OpSelectionMerge %66 None
+               OpBranchConditional %64 %65 %66
+         %65 = OpLabel
+         %68 = OpLoad %uint %a2_out
+         %69 = OpConvertUToF %float %68
+         %70 = OpFDiv %float %69 %float_255
+         %71 = OpCompositeConstruct %v4float %float_1 %float_0_200000003 %70 %float_1
+               OpStore %color %71
+               OpReturn
+         %66 = OpLabel
+               OpStore %color %73
+               OpReturn
+               OpFunctionEnd
+
+[fragment shader]
+#version 450
+
+layout (binding = 0, offset = 4) uniform atomic_uint a[3];
+
+layout (location = 0) uniform uint a0_expected;
+layout (location = 1) uniform uint a1_expected;
+layout (location = 2) uniform uint a2_expected;
+
+layout (location = 0) out vec4 color;
+
+void main()
+{
+	uint a0_out = atomicCounter(a[0]);
+	if (a0_out != a0_expected) {
+		color = vec4(1.0, 0.0, float(a0_out) / 255.0, 1.0);
+		return;
+	}
+
+	uint a1_out = atomicCounterIncrement(a[1]);
+	if (a1_out != a1_expected) {
+		color = vec4(1.0, 0.1, float(a1_out) / 255.0, 1.0);
+		return;
+	}
+
+	uint a2_out = atomicCounterDecrement(a[2]);
+	if (a2_out != a2_expected) {
+		color = vec4(1.0, 0.2, float(a2_out) / 255.0, 1.0);
+		return;
+	}
+
+	color = vec4(0.0, 1.0, 0.0, 1.0);
+}
+
+[test]
+
+clear color 0.0 0.0 0.0 0.0
+clear
+
+# Initialize atomic counters
+
+atomic counter buffer 0 4
+atomic counter 0 0 2
+atomic counter 0 1 3
+atomic counter 0 2 9
+atomic counter 0 3 15
+
+# Expected return values for the atomic counter operations
+
+uniform uint 0 3
+uniform uint 1 9
+uniform uint 2 14
+
+# Check original values for the atomic counters
+
+probe atomic counter buffer 0 0 == 2
+probe atomic counter buffer 0 4 == 3
+probe atomic counter buffer 0 8 == 9
+probe atomic counter buffer 0 12 == 15
+
+draw rect ortho 0 0 1 1
+
+# Check final values for the atomic counters
+
+probe atomic counter buffer 0 0 == 2
+probe atomic counter buffer 0 4 == 3
+probe atomic counter buffer 0 8 == 10
+probe atomic counter buffer 0 12 == 14
+
+probe rgba 0 0 0.0 1.0 0.0 1.0
diff --git a/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-fs.shader_runner b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-fs.shader_runner
new file mode 100644
index 000000000..9cf7139d0
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/uniform/atomic-uint-fs.shader_runner
@@ -0,0 +1,219 @@ 
+# Tests the atomic counter operations described in the
+# ARB_shader_atomic_counters specification in a FS.
+#
+# 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
+
+[vertex shader passthrough]
+
+[fragment 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 Fragment %main "main" %color
+               OpExecutionMode %main OriginLowerLeft
+               OpSource GLSL 450
+               OpName %main "main"
+               OpName %a0_out "a0_out"
+               OpName %a0 "a0"
+               OpName %a0_expected "a0_expected"
+               OpName %color "color"
+               OpName %a1_out "a1_out"
+               OpName %a1 "a1"
+               OpName %a1_expected "a1_expected"
+               OpName %b0_out "b0_out"
+               OpName %b0 "b0"
+               OpName %b0_expected "b0_expected"
+               OpDecorate %a0 Offset 4
+               OpDecorate %a0 DescriptorSet 0
+               OpDecorate %a0 Binding 0
+               OpDecorate %a0_expected Location 0
+               OpDecorate %a0_expected DescriptorSet 0
+               OpDecorate %a0_expected Binding 1
+               OpDecorate %color Location 0
+               OpDecorate %a1 Offset 12
+               OpDecorate %a1 DescriptorSet 0
+               OpDecorate %a1 Binding 0
+               OpDecorate %a1_expected Location 1
+               OpDecorate %a1_expected DescriptorSet 0
+               OpDecorate %a1_expected Binding 3
+               OpDecorate %b0 Offset 0
+               OpDecorate %b0 DescriptorSet 0
+               OpDecorate %b0 Binding 2
+               OpDecorate %b0_expected Location 2
+               OpDecorate %b0_expected DescriptorSet 0
+               OpDecorate %b0_expected Binding 4
+       %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
+%_ptr_UniformConstant_uint = OpTypePointer UniformConstant %uint
+%a0_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+       %bool = OpTypeBool
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_1 = OpConstant %float 1
+    %float_0 = OpConstant %float 0
+  %float_255 = OpConstant %float 255
+         %a1 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+%a1_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+%float_0_100000001 = OpConstant %float 0.100000001
+         %b0 = OpVariable %_ptr_AtomicCounter_uint AtomicCounter
+        %int = OpTypeInt 32 1
+      %int_1 = OpConstant %int 1
+%b0_expected = OpVariable %_ptr_UniformConstant_uint UniformConstant
+%float_0_200000003 = OpConstant %float 0.200000003
+         %67 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+     %a0_out = OpVariable %_ptr_Function_uint Function
+     %a1_out = OpVariable %_ptr_Function_uint Function
+     %b0_out = OpVariable %_ptr_Function_uint Function
+         %13 = OpAtomicLoad %uint %a0 %uint_1 %uint_0
+               OpStore %a0_out %13
+         %14 = OpLoad %uint %a0_out
+         %17 = OpLoad %uint %a0_expected
+         %19 = OpINotEqual %bool %14 %17
+               OpSelectionMerge %21 None
+               OpBranchConditional %19 %20 %21
+         %20 = OpLabel
+         %28 = OpLoad %uint %a0_out
+         %29 = OpConvertUToF %float %28
+         %31 = OpFDiv %float %29 %float_255
+         %32 = OpCompositeConstruct %v4float %float_1 %float_0 %31 %float_1
+               OpStore %color %32
+               OpReturn
+         %21 = OpLabel
+         %36 = OpAtomicIIncrement %uint %a1 %uint_1 %uint_0
+               OpStore %a1_out %36
+         %37 = OpLoad %uint %a1_out
+         %39 = OpLoad %uint %a1_expected
+         %40 = OpINotEqual %bool %37 %39
+               OpSelectionMerge %42 None
+               OpBranchConditional %40 %41 %42
+         %41 = OpLabel
+         %44 = OpLoad %uint %a1_out
+         %45 = OpConvertUToF %float %44
+         %46 = OpFDiv %float %45 %float_255
+         %47 = OpCompositeConstruct %v4float %float_1 %float_0_100000001 %46 %float_1
+               OpStore %color %47
+               OpReturn
+         %42 = OpLabel
+         %51 = OpAtomicIDecrement %uint %b0 %uint_1 %uint_0
+         %54 = OpISub %uint %51 %int_1
+               OpStore %b0_out %54
+         %55 = OpLoad %uint %b0_out
+         %57 = OpLoad %uint %b0_expected
+         %58 = OpINotEqual %bool %55 %57
+               OpSelectionMerge %60 None
+               OpBranchConditional %58 %59 %60
+         %59 = OpLabel
+         %62 = OpLoad %uint %b0_out
+         %63 = OpConvertUToF %float %62
+         %64 = OpFDiv %float %63 %float_255
+         %65 = OpCompositeConstruct %v4float %float_1 %float_0_200000003 %64 %float_1
+               OpStore %color %65
+               OpReturn
+         %60 = OpLabel
+               OpStore %color %67
+               OpReturn
+               OpFunctionEnd
+
+[fragment shader]
+#version 450
+
+layout (binding = 0, offset = 4) uniform atomic_uint a0;
+layout (binding = 0, offset = 12) uniform atomic_uint a1;
+layout (binding = 2, offset = 0) uniform atomic_uint b0;
+
+layout (location = 0) uniform uint a0_expected;
+layout (location = 1) uniform uint a1_expected;
+layout (location = 2) uniform uint b0_expected;
+
+layout (location = 0) out vec4 color;
+
+void main()
+{
+	uint a0_out = atomicCounter(a0);
+	if (a0_out != a0_expected) {
+		color = vec4(1.0, 0.0, float(a0_out) / 255.0, 1.0);
+		return;
+	}
+
+	uint a1_out = atomicCounterIncrement(a1);
+	if (a1_out != a1_expected) {
+		color = vec4(1.0, 0.1, float(a1_out) / 255.0, 1.0);
+		return;
+	}
+
+	uint b0_out = atomicCounterDecrement(b0);
+	if (b0_out != b0_expected) {
+		color = vec4(1.0, 0.2, float(b0_out) / 255.0, 1.0);
+		return;
+	}
+
+	color = vec4(0.0, 1.0, 0.0, 1.0);
+}
+
+[test]
+
+clear color 0.0 0.0 0.0 0.0
+clear
+
+# Initialize atomic counters
+
+atomic counter buffer 0 4
+atomic counter buffer 2 1
+
+atomic counter 0 0 0
+atomic counter 0 1 5   # a0
+atomic counter 0 2 0
+atomic counter 0 3 10  # a1
+atomic counter 2 0 15  # b0
+
+# Expected return values for the atomic counter operations
+
+uniform uint 0 5
+uniform uint 1 10
+uniform uint 2 14
+
+# Check original values for the atomic counters
+
+probe atomic counter buffer 0 0 == 0
+probe atomic counter buffer 0 4 == 5   # a0
+probe atomic counter buffer 0 8 == 0
+probe atomic counter buffer 0 12 == 10 # a1
+probe atomic counter buffer 2 0 == 15  # b0
+
+draw rect ortho 0 0 1 1
+
+# Check final values for the atomic counters
+
+probe atomic counter buffer 0 0 == 0
+probe atomic counter buffer 0 4 == 5   # a0
+probe atomic counter buffer 0 8 == 0
+probe atomic counter buffer 0 12 == 11 # a1
+probe atomic counter buffer 2 0 == 14  # b0
+
+probe rgba 0 0 0.0 1.0 0.0 1.0