Test message passing using permuted indices
authorAri Suonpaa <ari.suonpaa@siru.fi>
Thu, 10 Feb 2022 05:31:05 +0000 (07:31 +0200)
committerMatthew Netsch <quic_mnetsch@quicinc.com>
Thu, 24 Feb 2022 19:01:37 +0000 (19:01 +0000)
This change also adds support for a custom checkSupport
callback when creating Amber test cases.

VK-GL-CTS Issue: 3390

New tests:

dEQP-VK.memory_model.message_passing.permuted_index.*

Components: Vulkan, Framework
Change-Id: I68c13e0106acc4c2a2f7541c4acdf3274009ad7b

android/cts/main/vk-master-2021-03-01/memory-model.txt
android/cts/main/vk-master/memory-model.txt
external/vulkancts/data/vulkan/amber/memory_model/message_passing/permuted_index/barrier.amber [new file with mode: 0644]
external/vulkancts/data/vulkan/amber/memory_model/message_passing/permuted_index/release_acquire.amber [new file with mode: 0644]
external/vulkancts/data/vulkan/amber/memory_model/message_passing/permuted_index/release_acquire_atomic_payload.amber [new file with mode: 0644]
external/vulkancts/modules/vulkan/amber/vktAmberTestCase.cpp
external/vulkancts/modules/vulkan/amber/vktAmberTestCase.hpp
external/vulkancts/modules/vulkan/memory_model/CMakeLists.txt
external/vulkancts/modules/vulkan/memory_model/vktMemoryModelMessagePassing.cpp
external/vulkancts/mustpass/main/vk-default/memory-model.txt

index 1690bda..8de225c 100644 (file)
@@ -1,3 +1,6 @@
+dEQP-VK.memory_model.message_passing.permuted_index.barrier
+dEQP-VK.memory_model.message_passing.permuted_index.release_acquire
+dEQP-VK.memory_model.message_passing.permuted_index.release_acquire_atomic_payload
 dEQP-VK.memory_model.message_passing.ext.f32.coherent.atomic_atomic.atomicwrite.device.payload_nonlocal.buffer.guard_nonlocal.buffer.comp
 dEQP-VK.memory_model.message_passing.ext.f32.coherent.atomic_atomic.atomicwrite.device.payload_nonlocal.buffer.guard_nonlocal.buffer.vert
 dEQP-VK.memory_model.message_passing.ext.f32.coherent.atomic_atomic.atomicwrite.device.payload_nonlocal.buffer.guard_nonlocal.buffer.frag
index 0818fc2..c5e4ddf 100644 (file)
@@ -1,3 +1,6 @@
+dEQP-VK.memory_model.message_passing.permuted_index.barrier
+dEQP-VK.memory_model.message_passing.permuted_index.release_acquire
+dEQP-VK.memory_model.message_passing.permuted_index.release_acquire_atomic_payload
 dEQP-VK.memory_model.message_passing.core11.u32.coherent.fence_fence.atomicwrite.workgroup.payload_nonlocal.buffer.guard_nonlocal.buffer.comp
 dEQP-VK.memory_model.message_passing.core11.u32.coherent.fence_fence.atomicwrite.workgroup.payload_nonlocal.buffer.guard_nonlocal.image.comp
 dEQP-VK.memory_model.message_passing.core11.u32.coherent.fence_fence.atomicwrite.workgroup.payload_nonlocal.buffer.guard_nonlocal.workgroup.comp
diff --git a/external/vulkancts/data/vulkan/amber/memory_model/message_passing/permuted_index/barrier.amber b/external/vulkancts/data/vulkan/amber/memory_model/message_passing/permuted_index/barrier.amber
new file mode 100644 (file)
index 0000000..a297ff5
--- /dev/null
@@ -0,0 +1,87 @@
+#!amber
+
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+SHADER compute compute_shader GLSL
+#version 450
+#extension GL_KHR_memory_scope_semantics: enable
+
+layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in;
+
+struct S
+{
+    uint data;
+    uint flag;
+};
+
+layout(set = 0, binding = 0, std430) buffer Buf0
+{
+    S arr[];
+} buf;
+
+layout(set = 0, binding = 1, std430) buffer Buf1
+{
+    uint failures;
+} bufOut;
+
+uint permute(uint x)
+{
+    return (x * 419u) & 0xffff;
+}
+
+void main()
+{
+    // Message passing using data and flag pairs. The data is written to an index i, but the flag
+    // used for synchronization is from a different index calculated using permute(i).
+
+    uint i0 = gl_GlobalInvocationID.x;
+    atomicStore(buf.arr[i0].data, 1u, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsRelaxed);
+
+    // This barrier makes sure the order of the atomic store above and below does not change.
+    // This guarantees the data is always written before the flag.
+    memoryBarrierBuffer();
+
+    atomicStore(buf.arr[permute(i0)].flag, 1u, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsRelaxed);
+
+    // Read from an index which is presumably written by a different workgroup.
+    uint i1 = (i0 * 4099u) & 0xffff;
+    uint flag = atomicLoad(buf.arr[permute(i1)].flag, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsRelaxed);
+
+    // This barrier makes sure the atomic loads keep their execution order. That is, the flag is always read first.
+    memoryBarrierBuffer();
+
+    uint data = atomicLoad(buf.arr[i1].data, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsRelaxed);
+
+    // The flag should never be written before data.
+    if (flag > data)
+    {
+        atomicAdd(bufOut.failures, 1u);
+    }
+}
+END
+
+BUFFER buf0 DATA_TYPE uint32 SIZE 131072 FILL 0
+BUFFER buf1 DATA_TYPE uint32 SIZE 1 FILL 0
+
+PIPELINE compute pipeline
+  ATTACH compute_shader
+
+  BIND BUFFER buf0 AS storage DESCRIPTOR_SET 0 BINDING 0
+  BIND BUFFER buf1 AS storage DESCRIPTOR_SET 0 BINDING 1
+END
+
+RUN pipeline 256 1 1
+
+EXPECT buf1 IDX 0 EQ 0
diff --git a/external/vulkancts/data/vulkan/amber/memory_model/message_passing/permuted_index/release_acquire.amber b/external/vulkancts/data/vulkan/amber/memory_model/message_passing/permuted_index/release_acquire.amber
new file mode 100644 (file)
index 0000000..6e12c1b
--- /dev/null
@@ -0,0 +1,78 @@
+#!amber
+
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+SHADER compute compute_shader GLSL
+#version 450
+#extension GL_KHR_memory_scope_semantics: enable
+
+layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in;
+
+struct S
+{
+    uint data;
+    uint flag;
+};
+
+layout(set = 0, binding = 0, std430) buffer Buf0
+{
+    S arr[];
+} buf;
+
+layout(set = 0, binding = 1, std430) buffer Buf1
+{
+    uint failures;
+} bufOut;
+
+uint permute(uint x)
+{
+    return (x * 419u) & 0xffff;
+}
+
+void main()
+{
+    // Message passing using data and flag pairs. The data is written to an index i, but the flag
+    // used for synchronization is from a different index calculated using permute(i).
+
+    uint i0 = gl_GlobalInvocationID.x;
+    atomicStore(buf.arr[i0].data, 1u, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsRelaxed);
+    atomicStore(buf.arr[permute(i0)].flag, 1u, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsRelease);
+
+    // Read from an index which is presumably written by a different workgroup.
+    uint i1 = (i0 * 4099u) & 0xffff;
+    uint flag = atomicLoad(buf.arr[permute(i1)].flag, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsAcquire);
+    uint data = atomicLoad(buf.arr[i1].data, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsRelaxed);
+
+    // The flag should never be written before data.
+    if (flag > data)
+    {
+        atomicAdd(bufOut.failures, 1u);
+    }
+}
+END
+
+BUFFER buf0 DATA_TYPE uint32 SIZE 131072 FILL 0
+BUFFER buf1 DATA_TYPE uint32 SIZE 1 FILL 0
+
+PIPELINE compute pipeline
+  ATTACH compute_shader
+
+  BIND BUFFER buf0 AS storage DESCRIPTOR_SET 0 BINDING 0
+  BIND BUFFER buf1 AS storage DESCRIPTOR_SET 0 BINDING 1
+END
+
+RUN pipeline 256 1 1
+
+EXPECT buf1 IDX 0 EQ 0
diff --git a/external/vulkancts/data/vulkan/amber/memory_model/message_passing/permuted_index/release_acquire_atomic_payload.amber b/external/vulkancts/data/vulkan/amber/memory_model/message_passing/permuted_index/release_acquire_atomic_payload.amber
new file mode 100644 (file)
index 0000000..4a583a6
--- /dev/null
@@ -0,0 +1,78 @@
+#!amber
+
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+SHADER compute compute_shader GLSL
+#version 450
+#extension GL_KHR_memory_scope_semantics: enable
+
+layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in;
+
+struct S
+{
+    uint data;
+    uint flag;
+};
+
+layout(set = 0, binding = 0, std430) buffer Buf0
+{
+    S arr[];
+} buf;
+
+layout(set = 0, binding = 1, std430) buffer Buf1
+{
+    uint failures;
+} bufOut;
+
+uint permute(uint x)
+{
+    return (x * 419u) & 0xffff;
+}
+
+void main()
+{
+    // Message passing using data and flag pairs. The data is written to an index i, but the flag
+    // used for synchronization is from a different index calculated using permute(i).
+
+    uint i0 = gl_GlobalInvocationID.x;
+    buf.arr[i0].data = 1u;
+    atomicStore(buf.arr[permute(i0)].flag, 1u, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsRelease);
+
+    // Read from an index which is presumably written by a different workgroup.
+    uint i1 = (i0 * 4099u) & 0xffff;
+    uint flag = atomicLoad(buf.arr[permute(i1)].flag, gl_ScopeDevice, gl_StorageSemanticsBuffer, gl_SemanticsAcquire);
+    uint data = buf.arr[i1].data;
+
+    // The flag should never be written before data.
+    if (flag > data)
+    {
+        atomicAdd(bufOut.failures, 1u);
+    }
+}
+END
+
+BUFFER buf0 DATA_TYPE uint32 SIZE 131072 FILL 0
+BUFFER buf1 DATA_TYPE uint32 SIZE 1 FILL 0
+
+PIPELINE compute pipeline
+  ATTACH compute_shader
+
+  BIND BUFFER buf0 AS storage DESCRIPTOR_SET 0 BINDING 0
+  BIND BUFFER buf1 AS storage DESCRIPTOR_SET 0 BINDING 1
+END
+
+RUN pipeline 256 1 1
+
+EXPECT buf1 IDX 0 EQ 0
index a6813ca..697b6f1 100644 (file)
@@ -224,6 +224,9 @@ void AmberTestCase::checkSupport(Context& ctx) const
                                TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Stride is not multiply of minVertexInputBindingStrideAlignment");
                }
        }
+
+       if (m_checkSupportCallback)
+               (m_checkSupportCallback)(ctx, m_name);
 }
 
 class Delegate : public amber::Delegate
index 7b5888e..93410ad 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <string>
 #include <set>
+#include <functional>
 #include "tcuDefs.hpp"
 #include "tcuTestCase.hpp"
 #include "vkSpirVProgram.hpp"
@@ -79,6 +80,8 @@ public:
        //  - Otherwise, we do a secondary sanity check depending on code inside
        //    Amber itself: if the Amber test says it is not supported, then
        //    throw an internal error exception.
+       // A function pointer for a custom checkSupport function can also be
+       // provided for a more sophisticated support check.
        void checkSupport (Context& ctx) const override;
 
        // If the test case uses SPIR-V Assembly, use these build options.
@@ -96,6 +99,7 @@ public:
 
        void addImageRequirement(vk::VkImageCreateInfo info);
        void addBufferRequirement(BufferRequirement req);
+       void setCheckSupportCallback(std::function<void(Context&, std::string)> func)   { m_checkSupportCallback = func; }
 
        virtual bool validateRequirements() override;
 
@@ -104,26 +108,27 @@ public:
 private:
        bool parse (const std::string& readFilename);
 
-       amber::Recipe* m_recipe;
-       vk::SpirVAsmBuildOptions m_asm_options;
+       amber::Recipe*                                                          m_recipe;
+       vk::SpirVAsmBuildOptions                                        m_asm_options;
 
-       std::string m_readFilename;
+       std::string                                                                     m_readFilename;
 
        // Instance and device extensions required by the test.
        // We don't differentiate between the two:  We consider the requirement
        // satisfied if the string is registered as either an instance or device
        // extension.  Use a set for consistent ordering.
-       std::set<std::string> m_required_extensions;
+       std::set<std::string>                                           m_required_extensions;
 
        // Features required by the test.
        // A feature bit is represented by a string of form "<structure>.<feature>", where
        // the structure name matches the Vulkan spec, but without the leading "VkPhysicalDevice".
        // An example entry is: "VariablePointerFeatures.variablePointers".
        // Use a set for consistent ordering.
-       std::set<std::string> m_required_features;
+       std::set<std::string>                                           m_required_features;
 
-       std::vector<vk::VkImageCreateInfo> m_imageRequirements;
-       std::vector<BufferRequirement> m_bufferRequirements;
+       std::vector<vk::VkImageCreateInfo>                      m_imageRequirements;
+       std::vector<BufferRequirement>                          m_bufferRequirements;
+       std::function<void(Context&, std::string)>      m_checkSupportCallback  = nullptr;
 };
 
 AmberTestCase* createAmberTestCase (tcu::TestContext&                                                  testCtx,
index d45f589..631ef77 100755 (executable)
@@ -25,6 +25,7 @@
 #include "vktMemoryModelTests.hpp"
 #include "vktMemoryModelPadding.hpp"
 #include "vktMemoryModelSharedLayout.hpp"
+#include "vktAmberTestCase.hpp"
 
 #include "vkBufferWithMemory.hpp"
 #include "vkImageWithMemory.hpp"
@@ -1768,6 +1769,46 @@ tcu::TestStatus MemoryModelTestInstance::iterate (void)
        return tcu::TestStatus(res, qpGetTestResultName(res));
 }
 
+void checkPermutedIndexTestSupport (Context& context, std::string testName)
+{
+       DE_UNREF(testName);
+
+       const auto              maxComputeWorkGroupCount                = context.getDeviceProperties().limits.maxComputeWorkGroupCount;
+       const auto              maxComputeWorkGroupSize                 = context.getDeviceProperties().limits.maxComputeWorkGroupSize;
+       const auto              maxComputeWorkGroupInvocations  = context.getDeviceProperties().limits.maxComputeWorkGroupInvocations;
+
+       if (maxComputeWorkGroupCount[0] < 256u)
+               TCU_THROW(NotSupportedError, "Minimum of 256 required for maxComputeWorkGroupCount.x");
+
+       if (maxComputeWorkGroupSize[0] < 256u)
+               TCU_THROW(NotSupportedError, "Minimum of 256 required for maxComputeWorkGroupSize.x");
+
+       if (maxComputeWorkGroupInvocations < 256u)
+               TCU_THROW(NotSupportedError, "Minimum of 256 required for maxComputeWorkGroupInvocations");
+}
+
+tcu::TestCaseGroup* createPermutedIndexTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> permutedIndex (new tcu::TestCaseGroup(testCtx, "permuted_index", "Permuted index"));
+       static const char                       dataDir[]       = "memory_model/message_passing/permuted_index";
+       static const std::string        cases[]         =
+       {
+               "barrier",
+               "release_acquire",
+               "release_acquire_atomic_payload"
+       };
+
+       for (const auto& test : cases)
+       {
+               cts_amber::AmberTestCase* testCase = cts_amber::createAmberTestCase(testCtx, test.c_str(), "", dataDir, (test + ".amber").c_str());
+               testCase->setCheckSupportCallback(checkPermutedIndexTestSupport);
+
+               permutedIndex->addChild(testCase);
+       }
+
+       return permutedIndex.release();
+}
+
 }      // anonymous
 
 tcu::TestCaseGroup*    createTests (tcu::TestContext& testCtx)
@@ -1871,6 +1912,11 @@ tcu::TestCaseGroup*      createTests (tcu::TestContext& testCtx)
        for (int ttNdx = 0; ttNdx < DE_LENGTH_OF_ARRAY(ttCases); ttNdx++)
        {
                de::MovePtr<tcu::TestCaseGroup> ttGroup(new tcu::TestCaseGroup(testCtx, ttCases[ttNdx].name, ttCases[ttNdx].description));
+
+               // Permuted index tests for message passing.
+               if (ttCases[ttNdx].value == TT_MP)
+                       ttGroup->addChild(createPermutedIndexTests(testCtx));
+
                for (int core11Ndx = 0; core11Ndx < DE_LENGTH_OF_ARRAY(core11Cases); core11Ndx++)
                {
                        de::MovePtr<tcu::TestCaseGroup> core11Group(new tcu::TestCaseGroup(testCtx, core11Cases[core11Ndx].name, core11Cases[core11Ndx].description));
index 9030b22..843fa33 100644 (file)
@@ -1,3 +1,6 @@
+dEQP-VK.memory_model.message_passing.permuted_index.barrier
+dEQP-VK.memory_model.message_passing.permuted_index.release_acquire
+dEQP-VK.memory_model.message_passing.permuted_index.release_acquire_atomic_payload
 dEQP-VK.memory_model.message_passing.core11.u32.coherent.fence_fence.atomicwrite.device.payload_nonlocal.buffer.guard_nonlocal.buffer.comp
 dEQP-VK.memory_model.message_passing.core11.u32.coherent.fence_fence.atomicwrite.device.payload_nonlocal.buffer.guard_nonlocal.buffer.vert
 dEQP-VK.memory_model.message_passing.core11.u32.coherent.fence_fence.atomicwrite.device.payload_nonlocal.buffer.guard_nonlocal.buffer.frag