From 9fd74379c22af14f794d48fdc22e772d47f61ca3 Mon Sep 17 00:00:00 2001 From: ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:03:16 -0400 Subject: 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. --- tests/glsl-intrinsic/atomic/atomicCounter.slang | 132 +++++++ .../atomic/atomicCounterTestMultiple.slang | 33 ++ tests/glsl-intrinsic/atomic/atomicErrorTest1.slang | 13 + tests/glsl-intrinsic/atomic/atomicErrorTest2.slang | 13 + tests/glsl-intrinsic/atomic/atomicErrorTest3.slang | 13 + tests/glsl-intrinsic/atomic/atomicErrorTest4.slang | 13 + .../atomic/atomicStorageBuffer.slang | 381 +++++++++++++++++++++ 7 files changed, 598 insertions(+) create mode 100644 tests/glsl-intrinsic/atomic/atomicCounter.slang create mode 100644 tests/glsl-intrinsic/atomic/atomicCounterTestMultiple.slang create mode 100644 tests/glsl-intrinsic/atomic/atomicErrorTest1.slang create mode 100644 tests/glsl-intrinsic/atomic/atomicErrorTest2.slang create mode 100644 tests/glsl-intrinsic/atomic/atomicErrorTest3.slang create mode 100644 tests/glsl-intrinsic/atomic/atomicErrorTest4.slang create mode 100644 tests/glsl-intrinsic/atomic/atomicStorageBuffer.slang (limited to 'tests') 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 +} -- cgit v1.2.3