summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorArielG-NV <159081215+ArielG-NV@users.noreply.github.com>2024-03-13 15:03:16 -0400
committerGitHub <noreply@github.com>2024-03-13 15:03:16 -0400
commit9fd74379c22af14f794d48fdc22e772d47f61ca3 (patch)
tree9d15b4139d8fdaa335197617b0bc6cab14ed42a3 /tests
parent6f7c8271710b43349d34b8f7569ceb6957400548 (diff)
Implement glsl atomic's [non image or memory scope] with optional extension(s); resolves #3587 for GLSL & SPIR-V targets (#3755)
The following commit implements atomic operations & types associated with OpenGL 4.6, GL_EXT_vulkan_glsl_relaxed, GLSL_EXT_shader_atomic_float, GLSL_EXT_shader_atomic_float2, for GLSL & SPIR-V targets. Fully implements all functions, and built-in type's, resolves https://github.com/shader-slang/slang/issues/3560 for GLSL & SPRI-V targets. [Atomic extensions for GLSL can be found here](https://github.com/KhronosGroup/GLSL/tree/main) Notes of worth: * atomic_uint is well defined in GLSL->OpenGL, although was removed in GLSL->VK unless a compiler extension is supported (GL_EXT_vulkan_glsl_relaxed). This support entails transforming all atomic_uint operations and references into a storage buffer. SPIR-V has AtomicCounter+AtomicStorage (atomic_uint parallel) but does not implement these capabilities for SPIR-V->VK in any scenario. Due to the case we transform atomic_uint ourselves (GLSL_Syntax->Slang_IR) to accommodate transforming atomic_uint into valid syntax. * GLSL_EXT_shader_atomic_float2 (all float16_t & some float/double operations) support is minimal and worth watching out for if enabling the tests.
Diffstat (limited to 'tests')
-rw-r--r--tests/glsl-intrinsic/atomic/atomicCounter.slang132
-rw-r--r--tests/glsl-intrinsic/atomic/atomicCounterTestMultiple.slang33
-rw-r--r--tests/glsl-intrinsic/atomic/atomicErrorTest1.slang13
-rw-r--r--tests/glsl-intrinsic/atomic/atomicErrorTest2.slang13
-rw-r--r--tests/glsl-intrinsic/atomic/atomicErrorTest3.slang13
-rw-r--r--tests/glsl-intrinsic/atomic/atomicErrorTest4.slang13
-rw-r--r--tests/glsl-intrinsic/atomic/atomicStorageBuffer.slang381
7 files changed, 598 insertions, 0 deletions
diff --git a/tests/glsl-intrinsic/atomic/atomicCounter.slang b/tests/glsl-intrinsic/atomic/atomicCounter.slang
new file mode 100644
index 000000000..a3b938565
--- /dev/null
+++ b/tests/glsl-intrinsic/atomic/atomicCounter.slang
@@ -0,0 +1,132 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl -DTARGET_GLSL
+//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly -DTARGET_SPIRV
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly
+#version 430
+
+//TEST_INPUT:ubuffer(data=[0 0], stride=4):out,name=outputBuffer
+buffer MyBlockName
+{
+ uint data[2];
+} outputBuffer;
+
+// CHECK_GLSL-DAG: void main(
+// CHECK_SPV-DAG: OpEntryPoint
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):name=one
+layout(binding = 1, offset = 12) uniform atomic_uint one;
+bool testSetterAndGetter()
+{
+ return true
+
+// CHECK_GLSL-DAG: atomicExchange
+// CHECK_SPV-DAG: OpAtomicExchange
+ && atomicCounterExchange(one, 1) == 0
+
+// CHECK_GLSL-DAG: atomicExchange
+// no idea how to check the spirv reliabley...
+ && atomicCounter(one) == 1
+ && atomicCounterExchange(one, 5) == 1
+ && atomicCounter(one) == 5
+ ;
+}
+
+bool counterAsParam(atomic_uint param)
+{
+ return true
+ && atomicCounterExchange(param, 5) != 100
+
+// CHECK_GLSL-DAG: atomicAdd(
+// CHECK_SPV-DAG: OpAtomicIAdd
+ && atomicCounterIncrement(param) == 5
+ && atomicCounter(param) == 6
+ ;
+}
+
+// GLSL_CHECK-LABEL: bool testAtomicUint
+// SPV_CHECK-LABEL: testAtomicUint
+bool testAtomicUint()
+{
+// ensure the code emits for `one` index into [3] for 12/4
+// CHECK_GLSL-DAG: {{.*}}_data_0[3]{{.*}}
+ return true
+
+ && atomicCounterExchange(one, 5) != 100
+// CHECK_GLSL-DAG: atomicAdd(
+// CHECK_SPV-DAG: OpAtomicIIncrement
+ && atomicCounterIncrement(one) == 5
+ && atomicCounter(one) == 6
+
+ && atomicCounterExchange(one, 5) != 100
+// CHECK_GLSL-DAG: atomicExchange(
+// CHECK_SPV-DAG: OpAtomicIDecrement
+ && atomicCounterDecrement(one) == 4
+
+ && atomicCounterExchange(one, 5) != 100
+// CHECK_GLSL-DAG: atomicAdd(
+ && atomicCounterAdd(one, 1) == 5
+ && atomicCounter(one) == 6
+
+ && atomicCounterExchange(one, 5) != 100
+// CHECK_GLSL-DAG: atomicExchange
+// CHECK_SPV-DAG: OpAtomicISub
+ && atomicCounterSubtract(one, 1) == 5
+ && atomicCounter(one) == 4
+
+ && atomicCounterExchange(one, 5) != 100
+// CHECK_GLSL-DAG: atomicMin(
+// CHECK_SPV-DAG: OpAtomicUMin
+ && atomicCounterMin(one, 1) == 5
+ && atomicCounter(one) == 1
+
+ && atomicCounterExchange(one, 5) != 100
+// CHECK_GLSL-DAG: atomicMax(
+// CHECK_SPV-DAG: OpAtomicUMax
+ && atomicCounterMax(one, 1) == 5
+ && atomicCounter(one) == 5
+
+// CHECK_GLSL-DAG: atomicAnd(
+// CHECK_SPV: OpAtomicAnd
+ && atomicCounterExchange(one, 5) != 100
+ && atomicCounterAnd(one, 2) == 5
+ && atomicCounter(one) == 0
+
+// CHECK_GLSL-DAG: atomicOr(
+// CHECK_SPV-DAG: OpAtomicOr
+ && atomicCounterExchange(one, 5) != 100
+ && atomicCounterOr(one, 8) == 5
+ && atomicCounter(one) == 13
+
+// CHECK_GLSL-DAG: atomicXor(
+// CHECK_SPV-DAG: OpAtomicXor
+ && atomicCounterExchange(one, 5) != 100
+ && atomicCounterXor(one, 4) == 5
+ && atomicCounter(one) == 1
+
+// CHECK_GLSL-DAG: atomicCompSwap(
+// CHECK_SPV-DAG: OpAtomicCompareExchange
+ && atomicCounterExchange(one, 5) != 100
+ && atomicCounterCompSwap(one, 5, 3) == 5
+ && atomicCounter(one) == 3
+
+// CHECK_GLSL-DAG: atomicCompSwap(
+// CHECK_SPV-DAG: OpAtomicCompareExchange
+ && atomicCounterExchange(one, 5) != 100
+ && atomicCounterCompSwap(one, 5, 3) == 5
+ && atomicCounter(one) == 3
+
+ && counterAsParam(one);
+ ;
+}
+
+void computeMain()
+{
+ outputBuffer.data[0] = true
+ && testSetterAndGetter()
+ ;
+ outputBuffer.data[1] = true
+ && testAtomicUint()
+ ;
+ // BUF: 1
+ // BUF-NEXT: 1
+}
diff --git a/tests/glsl-intrinsic/atomic/atomicCounterTestMultiple.slang b/tests/glsl-intrinsic/atomic/atomicCounterTestMultiple.slang
new file mode 100644
index 000000000..ec296968c
--- /dev/null
+++ b/tests/glsl-intrinsic/atomic/atomicCounterTestMultiple.slang
@@ -0,0 +1,33 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl -DTARGET_GLSL
+#version 430
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
+buffer MyBlockName
+{
+ uint data[1];
+} outputBuffer;
+
+layout(binding = 1, offset = 12) uniform atomic_uint one;
+layout(binding = 1) uniform atomic_uint two;
+layout(binding = 1, offset = 4) uniform atomic_uint three;
+layout(binding = 1) uniform atomic_uint four;
+layout(binding = 2) uniform atomic_uint five;
+
+void computeMain()
+{
+
+ outputBuffer.data[0] = true
+// CHECK_GLSL: one_0._data_0[3]
+ && atomicCounter(one) == 0
+// CHECK_GLSL: one_0._data_0[4]
+ && atomicCounter(two) == 0
+// CHECK_GLSL: one_0._data_0[1]
+ && atomicCounter(three) == 0
+// CHECK_GLSL: one_0._data_0[2]
+ && atomicCounter(four) == 0
+// CHECK_GLSL: five_0._data_1[0]
+ && atomicCounter(five) == 0
+
+ ;
+
+}
diff --git a/tests/glsl-intrinsic/atomic/atomicErrorTest1.slang b/tests/glsl-intrinsic/atomic/atomicErrorTest1.slang
new file mode 100644
index 000000000..0512d598e
--- /dev/null
+++ b/tests/glsl-intrinsic/atomic/atomicErrorTest1.slang
@@ -0,0 +1,13 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target glsl -DTARGET_GLSL
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly -DTARGET_SPIRV
+#version 430
+
+// CHECK: error 20001
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):name=one
+layout(binding = 1, offset = ) uniform atomic_uint one;
+
+void computeMain()
+{
+
+}
diff --git a/tests/glsl-intrinsic/atomic/atomicErrorTest2.slang b/tests/glsl-intrinsic/atomic/atomicErrorTest2.slang
new file mode 100644
index 000000000..ca7d94e54
--- /dev/null
+++ b/tests/glsl-intrinsic/atomic/atomicErrorTest2.slang
@@ -0,0 +1,13 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target glsl -DTARGET_GLSL
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly -DTARGET_SPIRV
+#version 430
+
+// CHECK: error 20001
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):name=one
+layout(binding 1) uniform atomic_uint one;
+
+void computeMain()
+{
+
+}
diff --git a/tests/glsl-intrinsic/atomic/atomicErrorTest3.slang b/tests/glsl-intrinsic/atomic/atomicErrorTest3.slang
new file mode 100644
index 000000000..b21d27f6d
--- /dev/null
+++ b/tests/glsl-intrinsic/atomic/atomicErrorTest3.slang
@@ -0,0 +1,13 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target glsl -DTARGET_GLSL
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly -DTARGET_SPIRV
+#version 430
+
+// CHECK: error 20016
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):name=one
+layout(offset ) uniform atomic_uint one;
+
+void computeMain()
+{
+
+}
diff --git a/tests/glsl-intrinsic/atomic/atomicErrorTest4.slang b/tests/glsl-intrinsic/atomic/atomicErrorTest4.slang
new file mode 100644
index 000000000..404e2338c
--- /dev/null
+++ b/tests/glsl-intrinsic/atomic/atomicErrorTest4.slang
@@ -0,0 +1,13 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target glsl -DTARGET_GLSL
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly -DTARGET_SPIRV
+#version 430
+
+// CHECK: error 20001
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):name=one
+layout(binding = 1, offset) uniform atomic_uint one;
+
+void computeMain()
+{
+
+}
diff --git a/tests/glsl-intrinsic/atomic/atomicStorageBuffer.slang b/tests/glsl-intrinsic/atomic/atomicStorageBuffer.slang
new file mode 100644
index 000000000..5e00e1ec8
--- /dev/null
+++ b/tests/glsl-intrinsic/atomic/atomicStorageBuffer.slang
@@ -0,0 +1,381 @@
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -allow-glsl -stage compute -entry computeMain -target glsl -DTARGET_GLSL
+//TEST:SIMPLE(filecheck=CHECK_SPV): -allow-glsl -stage compute -entry computeMain -target spirv -emit-spirv-directly -DTARGET_SPIRV
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl
+//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=BUF):-vk -compute -entry computeMain -allow-glsl -emit-spirv-directly
+#version 430
+
+// float2 is currently a very new extension; most hardware lacks
+// this extension and will fail the test if attempting to use atomic_float2
+// operations
+// #define TEST_when_shader_atomic_float2_is_available
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
+buffer MyBlockName
+{
+ uint data[1];
+} outputBuffer;
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):name=int32Buffer
+buffer MyBlockName1
+{
+ int data[1];
+} int32Buffer;
+
+//TEST_INPUT:ubuffer(data=[0 0], stride=8):name=int64Buffer
+buffer MyBlockName2
+{
+ uint64_t data[1];
+} int64Buffer;
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):name=uint32Buffer
+buffer MyBlockName3
+{
+ uint data[1];
+} uint32Buffer;
+
+//TEST_INPUT:ubuffer(data=[0 0], stride=8):name=uint64Buffer
+buffer MyBlockName4
+{
+ uint64_t data[1];
+} uint64Buffer;
+
+//TEST_INPUT:ubuffer(data=[0.0], stride=2):name=float16Buffer
+buffer MyBlockName5
+{
+ half data[1];
+} float16Buffer;
+
+//TEST_INPUT:ubuffer(data=[0.0], stride=2):name=float32Buffer
+buffer MyBlockName6
+{
+ float data[1];
+} float32Buffer;
+
+//TEST_INPUT:ubuffer(data=[0.0 0.0], stride=8):name=float64Buffer
+buffer MyBlockName7
+{
+ double data[1];
+} float64Buffer;
+
+// added to tests `out TYPE data` due to Slang bug
+bool i32_init(int val, out int data)
+{
+ data = val;
+ return true;
+}
+bool i32_expect(int val)
+{
+ return int32Buffer.data[0] == val;
+}
+bool testAtomicInt32()
+{
+ return true
+
+ && i32_init(5, int32Buffer.data[0])
+ && atomicAdd(int32Buffer.data[0], 1) == 5
+ && i32_expect(6)
+
+ && i32_init(5, int32Buffer.data[0])
+ && atomicMin(int32Buffer.data[0], 1) == 5
+ && i32_expect(1)
+
+ && i32_init(5, int32Buffer.data[0])
+ && atomicMax(int32Buffer.data[0], 1) == 5
+ && i32_expect(5)
+
+ && i32_init(5, int32Buffer.data[0])
+ && atomicExchange(int32Buffer.data[0], 2) == 5
+ && i32_expect(2)
+
+ && i32_init(5, int32Buffer.data[0])
+ && atomicAnd(int32Buffer.data[0], 1) == 5
+ && i32_expect(1)
+
+ && i32_init(5, int32Buffer.data[0])
+ && atomicOr(int32Buffer.data[0], 2) == 5
+ && i32_expect(7)
+
+ && i32_init(5, int32Buffer.data[0])
+ && atomicXor(int32Buffer.data[0], 3) == 5
+ && i32_expect(6)
+
+ && i32_init(5, int32Buffer.data[0])
+ && atomicCompSwap(int32Buffer.data[0], 5, 2) == 5
+ && i32_expect(2)
+
+ && i32_init(5, int32Buffer.data[0])
+ && atomicCompSwap(int32Buffer.data[0], 4, 2) == 5
+ && i32_expect(5)
+ ;
+}
+
+bool i64_init(int64_t val, out int64_t data)
+{
+ data = val;
+ return true;
+}
+bool i64_expect(int64_t val)
+{
+ return int64Buffer.data[0] == val;
+}
+bool testAtomicInt64()
+{
+ return true
+
+ && i64_init(5, int64Buffer.data[0])
+ && atomicAdd(int64Buffer.data[0], 1) == 5
+ && i64_expect(6)
+
+ && i64_init(5, int64Buffer.data[0])
+ && atomicMin(int64Buffer.data[0], 1) == 5
+ && i64_expect(1)
+
+ && i64_init(5, int64Buffer.data[0])
+ && atomicMax(int64Buffer.data[0], 1) == 5
+ && i64_expect(5)
+
+ && i64_init(5, int64Buffer.data[0])
+ && atomicExchange(int64Buffer.data[0], 2) == 5
+ && i64_expect(2)
+
+ && i64_init(5, int64Buffer.data[0])
+ && atomicAnd(int64Buffer.data[0], 1) == 5
+ && i64_expect(1)
+
+ && i64_init(5, int64Buffer.data[0])
+ && atomicOr(int64Buffer.data[0], 2) == 5
+ && i64_expect(7)
+
+ && i64_init(5, int64Buffer.data[0])
+ && atomicXor(int64Buffer.data[0], 3) == 5
+ && i64_expect(6)
+
+ && i64_init(5, int64Buffer.data[0])
+ && atomicCompSwap(int64Buffer.data[0], 5, 2) == 5
+ && i64_expect(2)
+
+ && i64_init(5, int64Buffer.data[0])
+ && atomicCompSwap(int64Buffer.data[0], 4, 2) == 5
+ && i64_expect(5)
+ ;
+}
+
+bool u32_init(uint val, out uint data)
+{
+ data = val;
+ return true;
+}
+bool u32_expect(uint val)
+{
+ return uint32Buffer.data[0] == val;
+}
+bool testAtomicUint32()
+{
+ return true
+
+ && u32_init(5, uint32Buffer.data[0])
+ && atomicAdd(uint32Buffer.data[0], 1) == 5
+ && u32_expect(6)
+
+ && u32_init(5, uint32Buffer.data[0])
+ && atomicMin(uint32Buffer.data[0], 1) == 5
+ && u32_expect(1)
+
+ && u32_init(5, uint32Buffer.data[0])
+ && atomicMax(uint32Buffer.data[0], 1) == 5
+ && u32_expect(5)
+
+ && u32_init(5, uint32Buffer.data[0])
+ && atomicExchange(uint32Buffer.data[0], 2) == 5
+ && u32_expect(2)
+
+ && u32_init(5, uint32Buffer.data[0])
+ && atomicAnd(uint32Buffer.data[0], 1) == 5
+ && u32_expect(1)
+
+ && u32_init(5, uint32Buffer.data[0])
+ && atomicOr(uint32Buffer.data[0], 2) == 5
+ && u32_expect(7)
+
+ && u32_init(5, uint32Buffer.data[0])
+ && atomicXor(uint32Buffer.data[0], 3) == 5
+ && u32_expect(6)
+
+ && u32_init(5, uint32Buffer.data[0])
+ && atomicCompSwap(uint32Buffer.data[0], 5, 2) == 5
+ && u32_expect(2)
+
+ && u32_init(5, uint32Buffer.data[0])
+ && atomicCompSwap(uint32Buffer.data[0], 4, 2) == 5
+ && u32_expect(5)
+ ;
+}
+
+bool u64_init(uint64_t val, out uint64_t data)
+{
+ data = val;
+ return true;
+}
+bool u64_expect(uint64_t val)
+{
+ return uint64Buffer.data[0] == val;
+}
+bool testAtomicUint64()
+{
+ return true
+
+ && u64_init(5, uint64Buffer.data[0])
+ && atomicAdd(uint64Buffer.data[0], 1) == 5
+ && u64_expect(6)
+
+ && u64_init(5, uint64Buffer.data[0])
+ && atomicMin(uint64Buffer.data[0], 1) == 5
+ && u64_expect(1)
+
+ && u64_init(5, uint64Buffer.data[0])
+ && atomicMax(uint64Buffer.data[0], 1) == 5
+ && u64_expect(5)
+
+ && u64_init(5, uint64Buffer.data[0])
+ && atomicExchange(uint64Buffer.data[0], 2) == 5
+ && u64_expect(2)
+
+ && u64_init(5, uint64Buffer.data[0])
+ && atomicAnd(uint64Buffer.data[0], 1) == 5
+ && u64_expect(1)
+
+ && u64_init(5, uint64Buffer.data[0])
+ && atomicOr(uint64Buffer.data[0], 2) == 5
+ && u64_expect(7)
+
+ && u64_init(5, uint64Buffer.data[0])
+ && atomicXor(uint64Buffer.data[0], 3) == 5
+ && u64_expect(6)
+
+ && u64_init(5, uint64Buffer.data[0])
+ && atomicCompSwap(uint64Buffer.data[0], 5, 2) == 5
+ && u64_expect(2)
+
+ && u64_init(5, uint64Buffer.data[0])
+ && atomicCompSwap(uint64Buffer.data[0], 4, 2) == 5
+ && u64_expect(5)
+ ;
+}
+
+bool f16_init(half val, out half data)
+{
+ data = val;
+ return true;
+}
+bool f16_expect(half val)
+{
+ return float16Buffer.data[0] == val;
+}
+bool testAtomicFloat16()
+{
+ return true
+
+#ifdef TEST_when_shader_atomic_float2_is_available
+ && f16_init(5, float16Buffer.data[0])
+ && atomicAdd(float16Buffer.data[0], half(1)) == half(5)
+ && f16_expect(6)
+
+ && f16_init(5, float16Buffer.data[0])
+ && atomicMin(float16Buffer.data[0], half(1)) == half(5)
+ && f16_expect(1)
+
+ && f16_init(5, float16Buffer.data[0])
+ && atomicMax(float16Buffer.data[0], half(1)) == half(5)
+ && f16_expect(5)
+
+ && f16_init(5, float16Buffer.data[0])
+ && atomicExchange(float16Buffer.data[0], half(2)) == half(5)
+ && f16_expect(2)
+#endif // TEST_when_shader_atomic_float2_is_available
+ ;
+}
+
+bool f32_init(float val, out float data)
+{
+ data = val;
+ return true;
+}
+bool f32_expect(float val)
+{
+ return float32Buffer.data[0] == val;
+}
+bool testAtomicFloat32()
+{
+ return true
+
+ && f32_init(5, float32Buffer.data[0])
+ && atomicAdd(float32Buffer.data[0], float(1)) == float(5)
+ && f32_expect(6)
+
+#ifdef TEST_when_shader_atomic_float2_is_available
+ && f32_init(5, float32Buffer.data[0])
+ && atomicMin(float32Buffer.data[0], float(1)) == float(5)
+ && f32_expect(1)
+
+ && f32_init(5, float32Buffer.data[0])
+ && atomicMax(float32Buffer.data[0], float(1)) == float(5)
+ && f32_expect(5)
+
+ && f32_init(5, float32Buffer.data[0])
+ && atomicExchange(float32Buffer.data[0], float(2)) == float(5)
+ && f32_expect(2)
+#endif // TEST_when_shader_atomic_float2_is_available
+ ;
+}
+
+bool f64_init(double val, out double data)
+{
+ data = val;
+ return true;
+}
+bool f64_expect(double val)
+{
+ return float64Buffer.data[0] == val;
+}
+bool testAtomicFloat64()
+{
+ return true
+
+ && f64_init(5, float64Buffer.data[0])
+ && atomicAdd(float64Buffer.data[0], double(1)) == double(5)
+ && f64_expect(6)
+
+#ifdef TEST_when_shader_atomic_float2_is_available
+ && f64_init(5, float64Buffer.data[0])
+ && atomicMin(float64Buffer.data[0], double(1)) == double(5)
+ && f64_expect(1)
+
+ && f64_init(5, float64Buffer.data[0])
+ && atomicMax(float64Buffer.data[0], double(1)) == double(5)
+ && f64_expect(5)
+
+ && f64_init(5, float64Buffer.data[0])
+ && atomicExchange(float64Buffer.data[0], double(2)) == double(5)
+ && f64_expect(2)
+#endif // TEST_when_shader_atomic_float2_is_available
+ ;
+}
+
+layout(local_size_x = 1) in;
+void computeMain()
+{
+ // testing has the following pattern in 3 lines per operation:
+ // set the value, operation on value, test the result
+ outputBuffer.data[0] = true
+ && testAtomicInt32()
+ && testAtomicInt64()
+ && testAtomicUint32()
+ && testAtomicUint64()
+ && testAtomicFloat16()
+ && testAtomicFloat32()
+ && testAtomicFloat64()
+ ;
+ // CHECK_GLSL: void main(
+ // CHECK_SPV: OpEntryPoint
+ // BUF: 1
+}