Added OpAtomic* test for graphics pipeline
authorAri Suonpää <ari.suonpaa@siru.fi>
Tue, 13 Jun 2017 05:24:56 +0000 (08:24 +0300)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Tue, 4 Jul 2017 13:48:48 +0000 (09:48 -0400)
Affects:

dEQP-VK.glsl.atomic_operations.*

Components: Vulkan

VK-GL-CTS issue: 360

Change-Id: I833204021e978d0231fbe86e18ad116a034996fe

AndroidGen.mk
android/cts/master/vk-master.txt
external/vulkancts/modules/vulkan/shaderexecutor/CMakeLists.txt
external/vulkancts/modules/vulkan/shaderexecutor/vktAtomicOperationTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktAtomicOperationTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/vktTestPackage.cpp
external/vulkancts/mustpass/1.0.3/vk-default.txt

index ab257d7..eedbb87 100644 (file)
@@ -165,6 +165,7 @@ LOCAL_SRC_FILES := \
        external/vulkancts/modules/vulkan/robustness/vktRobustnessTests.cpp \
        external/vulkancts/modules/vulkan/robustness/vktRobustnessUtil.cpp \
        external/vulkancts/modules/vulkan/robustness/vktRobustnessVertexAccessTests.cpp \
+       external/vulkancts/modules/vulkan/shaderexecutor/vktAtomicOperationTests.cpp \
        external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.cpp \
        external/vulkancts/modules/vulkan/shaderexecutor/vktShaderBuiltinPrecisionTests.cpp \
        external/vulkancts/modules/vulkan/shaderexecutor/vktShaderBuiltinTests.cpp \
index a820c12..914e3e0 100644 (file)
@@ -149862,6 +149862,102 @@ dEQP-VK.glsl.opaque_type_indexing.atomic_counter.dynamically_uniform_geometry
 dEQP-VK.glsl.opaque_type_indexing.atomic_counter.dynamically_uniform_tess_ctrl
 dEQP-VK.glsl.opaque_type_indexing.atomic_counter.dynamically_uniform_tess_eval
 dEQP-VK.glsl.opaque_type_indexing.atomic_counter.dynamically_uniform_compute
+dEQP-VK.glsl.atomic_operations.exchange_signed_vertex
+dEQP-VK.glsl.atomic_operations.exchange_signed_fragment
+dEQP-VK.glsl.atomic_operations.exchange_signed_geometry
+dEQP-VK.glsl.atomic_operations.exchange_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.exchange_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.exchange_signed_compute
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_compute
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_vertex
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_fragment
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_geometry
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_compute
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_compute
+dEQP-VK.glsl.atomic_operations.add_signed_vertex
+dEQP-VK.glsl.atomic_operations.add_signed_fragment
+dEQP-VK.glsl.atomic_operations.add_signed_geometry
+dEQP-VK.glsl.atomic_operations.add_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.add_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.add_signed_compute
+dEQP-VK.glsl.atomic_operations.add_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.add_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.add_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.add_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.add_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.add_unsigned_compute
+dEQP-VK.glsl.atomic_operations.min_signed_vertex
+dEQP-VK.glsl.atomic_operations.min_signed_fragment
+dEQP-VK.glsl.atomic_operations.min_signed_geometry
+dEQP-VK.glsl.atomic_operations.min_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.min_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.min_signed_compute
+dEQP-VK.glsl.atomic_operations.min_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.min_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.min_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.min_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.min_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.min_unsigned_compute
+dEQP-VK.glsl.atomic_operations.max_signed_vertex
+dEQP-VK.glsl.atomic_operations.max_signed_fragment
+dEQP-VK.glsl.atomic_operations.max_signed_geometry
+dEQP-VK.glsl.atomic_operations.max_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.max_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.max_signed_compute
+dEQP-VK.glsl.atomic_operations.max_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.max_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.max_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.max_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.max_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.max_unsigned_compute
+dEQP-VK.glsl.atomic_operations.and_signed_vertex
+dEQP-VK.glsl.atomic_operations.and_signed_fragment
+dEQP-VK.glsl.atomic_operations.and_signed_geometry
+dEQP-VK.glsl.atomic_operations.and_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.and_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.and_signed_compute
+dEQP-VK.glsl.atomic_operations.and_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.and_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.and_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.and_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.and_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.and_unsigned_compute
+dEQP-VK.glsl.atomic_operations.or_signed_vertex
+dEQP-VK.glsl.atomic_operations.or_signed_fragment
+dEQP-VK.glsl.atomic_operations.or_signed_geometry
+dEQP-VK.glsl.atomic_operations.or_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.or_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.or_signed_compute
+dEQP-VK.glsl.atomic_operations.or_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.or_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.or_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.or_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.or_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.or_unsigned_compute
+dEQP-VK.glsl.atomic_operations.xor_signed_vertex
+dEQP-VK.glsl.atomic_operations.xor_signed_fragment
+dEQP-VK.glsl.atomic_operations.xor_signed_geometry
+dEQP-VK.glsl.atomic_operations.xor_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.xor_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.xor_signed_compute
+dEQP-VK.glsl.atomic_operations.xor_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.xor_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.xor_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.xor_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.xor_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.xor_unsigned_compute
 dEQP-VK.renderpass.simple.color
 dEQP-VK.renderpass.simple.depth
 dEQP-VK.renderpass.simple.stencil
index ec1bc9e..3951681 100644 (file)
@@ -15,6 +15,8 @@ set(DEQP_VK_SHADEREXECUTOR_SRCS
        vktShaderBuiltinPrecisionTests.hpp
        vktOpaqueTypeIndexingTests.cpp
        vktOpaqueTypeIndexingTests.hpp
+       vktAtomicOperationTests.cpp
+       vktAtomicOperationTests.hpp
 )
 
 set(DEQP_VK_SHADEREXECUTOR_LIBS
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktAtomicOperationTests.cpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktAtomicOperationTests.cpp
new file mode 100644 (file)
index 0000000..46846ce
--- /dev/null
@@ -0,0 +1,652 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2017 Google Inc.
+ *
+ * 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.
+ *
+ *//*!
+ * \file
+ * \brief Atomic operations (OpAtomic*) tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktAtomicOperationTests.hpp"
+#include "vktShaderExecutor.hpp"
+
+#include "vkRefUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vktTestGroupUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuStringTemplate.hpp"
+#include "tcuResultCollector.hpp"
+
+#include "deStringUtil.hpp"
+#include "deSharedPtr.hpp"
+#include "deRandom.hpp"
+#include "deArrayUtil.hpp"
+
+#include <string>
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+namespace
+{
+
+using de::UniquePtr;
+using de::MovePtr;
+using std::vector;
+
+using namespace vk;
+
+// Buffer helper
+class Buffer
+{
+public:
+                                               Buffer                          (Context& context, VkBufferUsageFlags usage, size_t size);
+
+       VkBuffer                        getBuffer                       (void) const { return *m_buffer;                                        }
+       void*                           getHostPtr                      (void) const { return m_allocation->getHostPtr();       }
+       void                            flush                           (void);
+       void                            invalidate                      (void);
+
+private:
+       const DeviceInterface&          m_vkd;
+       const VkDevice                          m_device;
+       const Unique<VkBuffer>          m_buffer;
+       const UniquePtr<Allocation>     m_allocation;
+};
+
+typedef de::SharedPtr<Buffer> BufferSp;
+
+Move<VkBuffer> createBuffer (const DeviceInterface& vkd, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usageFlags)
+{
+       const VkBufferCreateInfo createInfo     =
+       {
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+               DE_NULL,
+               (VkBufferCreateFlags)0,
+               size,
+               usageFlags,
+               VK_SHARING_MODE_EXCLUSIVE,
+               0u,
+               DE_NULL
+       };
+       return createBuffer(vkd, device, &createInfo);
+}
+
+MovePtr<Allocation> allocateAndBindMemory (const DeviceInterface& vkd, VkDevice device, Allocator& allocator, VkBuffer buffer)
+{
+       MovePtr<Allocation>     alloc(allocator.allocate(getBufferMemoryRequirements(vkd, device, buffer), MemoryRequirement::HostVisible));
+
+       VK_CHECK(vkd.bindBufferMemory(device, buffer, alloc->getMemory(), alloc->getOffset()));
+
+       return alloc;
+}
+
+Buffer::Buffer (Context& context, VkBufferUsageFlags usage, size_t size)
+       : m_vkd                 (context.getDeviceInterface())
+       , m_device              (context.getDevice())
+       , m_buffer              (createBuffer                   (context.getDeviceInterface(),
+                                                                                        context.getDevice(),
+                                                                                        (VkDeviceSize)size,
+                                                                                        usage))
+       , m_allocation  (allocateAndBindMemory  (context.getDeviceInterface(),
+                                                                                        context.getDevice(),
+                                                                                        context.getDefaultAllocator(),
+                                                                                        *m_buffer))
+{
+}
+
+void Buffer::flush (void)
+{
+       flushMappedMemoryRange(m_vkd, m_device, m_allocation->getMemory(), m_allocation->getOffset(), VK_WHOLE_SIZE);
+}
+
+void Buffer::invalidate (void)
+{
+       invalidateMappedMemoryRange(m_vkd, m_device, m_allocation->getMemory(), m_allocation->getOffset(), VK_WHOLE_SIZE);
+}
+
+// Tests
+
+enum AtomicOperation
+{
+       ATOMIC_OP_EXCHANGE = 0,
+       ATOMIC_OP_COMP_SWAP,
+       ATOMIC_OP_ADD,
+       ATOMIC_OP_MIN,
+       ATOMIC_OP_MAX,
+       ATOMIC_OP_AND,
+       ATOMIC_OP_OR,
+       ATOMIC_OP_XOR,
+
+       ATOMIC_OP_LAST
+};
+
+std::string atomicOp2Str (AtomicOperation op)
+{
+       static const char* const s_names[] =
+       {
+               "atomicExchange",
+               "atomicCompSwap",
+               "atomicAdd",
+               "atomicMin",
+               "atomicMax",
+               "atomicAnd",
+               "atomicOr",
+               "atomicXor"
+       };
+       return de::getSizedArrayElement<ATOMIC_OP_LAST>(s_names, op);
+}
+
+enum
+{
+       NUM_ELEMENTS = 32
+};
+
+class AtomicOperationCaseInstance : public TestInstance
+{
+public:
+                                                                       AtomicOperationCaseInstance             (Context&                       context,
+                                                                                                                                        const ShaderSpec&      shaderSpec,
+                                                                                                                                        glu::ShaderType        shaderType,
+                                                                                                                                        bool                           sign,
+                                                                                                                                        AtomicOperation        atomicOp);
+       virtual                                                 ~AtomicOperationCaseInstance    (void);
+
+       virtual tcu::TestStatus                 iterate                                                 (void);
+
+private:
+       const ShaderSpec&                               m_shaderSpec;
+       glu::ShaderType                                 m_shaderType;
+       bool                                                    m_sign;
+       AtomicOperation                                 m_atomicOp;
+
+       struct BufferInterface
+       {
+               // Use half the number of elements for inout to cause overlap between atomic operations.
+               // Each inout element at index i will have two atomic operations using input from
+               // indices i and i + NUM_ELEMENTS / 2.
+               deInt32         index;
+               deUint32        inout[NUM_ELEMENTS / 2];
+               deUint32        input[NUM_ELEMENTS];
+               deUint32        compare[NUM_ELEMENTS];
+               deUint32        output[NUM_ELEMENTS];
+       };
+
+       template<typename T>
+       struct Expected
+       {
+               T m_inout;
+               T m_output[2];
+
+               Expected (T inout, T output0, T output1)
+               : m_inout(inout)
+               {
+                       m_output[0] = output0;
+                       m_output[1] = output1;
+               }
+
+               bool compare (deUint32 inout, deUint32 output0, deUint32 output1)
+               {
+                       return (deMemCmp((const void*)&m_inout, (const void*)&inout, sizeof(inout)) == 0
+                                       && deMemCmp((const void*)&m_output[0], (const void*)&output0, sizeof(output0)) == 0
+                                       && deMemCmp((const void*)&m_output[1], (const void*)&output1, sizeof(output1)) == 0);
+               }
+       };
+
+       template<typename T> void checkOperation        (const BufferInterface& original,
+                                                                                                const BufferInterface& result,
+                                                                                                tcu::ResultCollector&  resultCollector);
+
+};
+
+AtomicOperationCaseInstance::AtomicOperationCaseInstance (Context&                     context,
+                                                                                                                 const ShaderSpec&     shaderSpec,
+                                                                                                                 glu::ShaderType       shaderType,
+                                                                                                                 bool                          sign,
+                                                                                                                 AtomicOperation       atomicOp)
+       : TestInstance  (context)
+       , m_shaderSpec  (shaderSpec)
+       , m_shaderType  (shaderType)
+       , m_sign                (sign)
+       , m_atomicOp    (atomicOp)
+{
+}
+
+AtomicOperationCaseInstance::~AtomicOperationCaseInstance (void)
+{
+}
+
+// Use template to handle both signed and unsigned cases. SPIR-V should
+// have separate operations for both.
+template<typename T>
+void AtomicOperationCaseInstance::checkOperation (const BufferInterface&       original,
+                                                                                                 const BufferInterface&        result,
+                                                                                                 tcu::ResultCollector&         resultCollector)
+{
+       // originalInout = original inout
+       // input0 = input at index i
+       // iinput1 = input at index i + NUM_ELEMENTS / 2
+       //
+       // atomic operation will return the memory contents before
+       // the operation and this is stored as output. Two operations
+       // are executed for each InOut value (using input0 and input1).
+       //
+       // Since there is an overlap of two operations per each
+       // InOut element, the outcome of the resulting InOut and
+       // the outputs of the operations have two result candidates
+       // depending on the execution order. Verification passes
+       // if the results match one of these options.
+
+       for (int elementNdx = 0; elementNdx < NUM_ELEMENTS / 2; elementNdx++)
+       {
+               // Needed when reinterpeting the data as signed values.
+               const T originalInout   = *reinterpret_cast<const T*>(&original.inout[elementNdx]);
+               const T input0                  = *reinterpret_cast<const T*>(&original.input[elementNdx]);
+               const T input1                  = *reinterpret_cast<const T*>(&original.input[elementNdx + NUM_ELEMENTS / 2]);
+
+               // Expected results are collected to this vector.
+               vector<Expected<T> > exp;
+
+               switch (m_atomicOp)
+               {
+                       case ATOMIC_OP_ADD:
+                       {
+                               exp.push_back(Expected<T>(originalInout + input0 + input1, originalInout, originalInout + input0));
+                               exp.push_back(Expected<T>(originalInout + input0 + input1, originalInout + input1, originalInout));
+                       }
+                       break;
+
+                       case ATOMIC_OP_AND:
+                       {
+                               exp.push_back(Expected<T>(originalInout & input0 & input1, originalInout, originalInout & input0));
+                               exp.push_back(Expected<T>(originalInout & input0 & input1, originalInout & input1, originalInout));
+                       }
+                       break;
+
+                       case ATOMIC_OP_OR:
+                       {
+                               exp.push_back(Expected<T>(originalInout | input0 | input1, originalInout, originalInout | input0));
+                               exp.push_back(Expected<T>(originalInout | input0 | input1, originalInout | input1, originalInout));
+                       }
+                       break;
+
+                       case ATOMIC_OP_XOR:
+                       {
+                               exp.push_back(Expected<T>(originalInout ^ input0 ^ input1, originalInout, originalInout ^ input0));
+                               exp.push_back(Expected<T>(originalInout ^ input0 ^ input1, originalInout ^ input1, originalInout));
+                       }
+                       break;
+
+                       case ATOMIC_OP_MIN:
+                       {
+                               exp.push_back(Expected<T>(de::min(de::min(originalInout, input0), input1), originalInout, de::min(originalInout, input0)));
+                               exp.push_back(Expected<T>(de::min(de::min(originalInout, input0), input1), de::min(originalInout, input1), originalInout));
+                       }
+                       break;
+
+                       case ATOMIC_OP_MAX:
+                       {
+                               exp.push_back(Expected<T>(de::max(de::max(originalInout, input0), input1), originalInout, de::max(originalInout, input0)));
+                               exp.push_back(Expected<T>(de::max(de::max(originalInout, input0), input1), de::max(originalInout, input1), originalInout));
+                       }
+                       break;
+
+                       case ATOMIC_OP_EXCHANGE:
+                       {
+                               exp.push_back(Expected<T>(input1, originalInout, input0));
+                               exp.push_back(Expected<T>(input0, input1, originalInout));
+                       }
+                       break;
+
+                       case ATOMIC_OP_COMP_SWAP:
+                       {
+                               if (elementNdx % 2 == 0)
+                               {
+                                       exp.push_back(Expected<T>(input0, originalInout, input0));
+                                       exp.push_back(Expected<T>(input0, originalInout, originalInout));
+                               }
+                               else
+                               {
+                                       exp.push_back(Expected<T>(input1, input1, originalInout));
+                                       exp.push_back(Expected<T>(input1, originalInout, originalInout));
+                               }
+                       }
+                       break;
+
+
+                       default:
+                               DE_FATAL("Unexpected atomic operation.");
+                               break;
+               };
+
+               const deUint32 resIo            = result.inout[elementNdx];
+               const deUint32 resOutput0       = result.output[elementNdx];
+               const deUint32 resOutput1       = result.output[elementNdx + NUM_ELEMENTS / 2];
+
+               if (!exp[0].compare(resIo, resOutput0, resOutput1) && !exp[1].compare(resIo, resOutput0, resOutput1))
+               {
+                       std::ostringstream errorMessage;
+                       errorMessage    << "ERROR: Result value check failed at index " << elementNdx
+                                                       << ". Expected one of the two outcomes: InOut = " << tcu::toHex(exp[0].m_inout)
+                                                       << ", Output0 = " << tcu::toHex(exp[0].m_output[0]) << ", Output1 = "
+                                                       << tcu::toHex(exp[0].m_output[1]) << ", or InOut = " << tcu::toHex(exp[1].m_inout)
+                                                       << ", Output0 = " << tcu::toHex(exp[1].m_output[0]) << ", Output1 = "
+                                                       << tcu::toHex(exp[1].m_output[1]) << ". Got: InOut = " << tcu::toHex(resIo)
+                                                       << ", Output0 = " << tcu::toHex(resOutput0) << ", Output1 = "
+                                                       << tcu::toHex(resOutput1) << ". Using Input0 = " << tcu::toHex(original.input[elementNdx])
+                                                       << " and Input1 = " << tcu::toHex(original.input[elementNdx + NUM_ELEMENTS / 2]) << ".";
+
+                       resultCollector.fail(errorMessage.str());
+               }
+       }
+}
+
+tcu::TestStatus AtomicOperationCaseInstance::iterate (void)
+{
+       //Check stores and atomic operation support.
+       switch (m_shaderType)
+       {
+               case glu::SHADERTYPE_VERTEX:
+               case glu::SHADERTYPE_TESSELLATION_CONTROL:
+               case glu::SHADERTYPE_TESSELLATION_EVALUATION:
+               case glu::SHADERTYPE_GEOMETRY:
+                       if(!m_context.getDeviceFeatures().vertexPipelineStoresAndAtomics)
+                               TCU_THROW(NotSupportedError, "Stores and atomic operations are not supported in Vertex, Tessellation, and Geometry shader.");
+                       break;
+               case glu::SHADERTYPE_FRAGMENT:
+                       if(!m_context.getDeviceFeatures().fragmentStoresAndAtomics)
+                               TCU_THROW(NotSupportedError, "Stores and atomic operations are not supported in fragment shader.");
+                       break;
+               case glu::SHADERTYPE_COMPUTE:
+                       break;
+               default:
+                       DE_FATAL("Unsupported shader type");
+       }
+
+       tcu::TestLog&                           log                     = m_context.getTestContext().getLog();
+       const DeviceInterface&          vkd                     = m_context.getDeviceInterface();
+       const VkDevice                          device          = m_context.getDevice();
+       de::Random                                      rnd                     (0x62a15e34);
+       Buffer                                          buffer          (m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, sizeof(BufferInterface));
+       BufferInterface*                        ptr                     = (BufferInterface*)buffer.getHostPtr();
+
+       for (int i = 0; i < NUM_ELEMENTS / 2; i++)
+       {
+               ptr->inout[i] = rnd.getUint32();
+               // The first half of compare elements match with every even index.
+               // The second half matches with odd indices. This causes the
+               // overlapping operations to only select one.
+               ptr->compare[i] = ptr->inout[i] + (i % 2);
+               ptr->compare[i + NUM_ELEMENTS / 2] = ptr->inout[i] + 1 - (i % 2);
+       }
+       for (int i = 0; i < NUM_ELEMENTS; i++)
+       {
+               ptr->input[i] = rnd.getUint32();
+               ptr->output[i] = 0xcdcdcdcd;
+       }
+       ptr->index = 0;
+
+       // Take a copy to be used when calculating expected values.
+       BufferInterface original = *ptr;
+
+       buffer.flush();
+
+       Move<VkDescriptorSetLayout>     extraResourcesLayout;
+       Move<VkDescriptorPool>          extraResourcesSetPool;
+       Move<VkDescriptorSet>           extraResourcesSet;
+
+       const VkDescriptorSetLayoutBinding bindings[] =
+       {
+               { 0u, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, DE_NULL }
+       };
+
+       const VkDescriptorSetLayoutCreateInfo   layoutInfo      =
+       {
+               VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+               DE_NULL,
+               (VkDescriptorSetLayoutCreateFlags)0u,
+               DE_LENGTH_OF_ARRAY(bindings),
+               bindings
+       };
+
+       extraResourcesLayout = createDescriptorSetLayout(vkd, device, &layoutInfo);
+
+       const VkDescriptorPoolSize poolSizes[] =
+       {
+               { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u }
+       };
+       const VkDescriptorPoolCreateInfo poolInfo =
+       {
+               VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+               DE_NULL,
+               (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
+               1u,             // maxSets
+               DE_LENGTH_OF_ARRAY(poolSizes),
+               poolSizes
+       };
+
+       extraResourcesSetPool = createDescriptorPool(vkd, device, &poolInfo);
+
+       const VkDescriptorSetAllocateInfo allocInfo =
+       {
+               VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+               DE_NULL,
+               *extraResourcesSetPool,
+               1u,
+               &extraResourcesLayout.get()
+       };
+
+       extraResourcesSet = allocateDescriptorSet(vkd, device, &allocInfo);
+
+       VkDescriptorBufferInfo bufferInfo;
+       bufferInfo.buffer       = buffer.getBuffer();
+       bufferInfo.offset       = 0u;
+       bufferInfo.range        = VK_WHOLE_SIZE;
+
+       const VkWriteDescriptorSet descriptorWrite =
+       {
+               VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+               DE_NULL,
+               *extraResourcesSet,
+               0u,             // dstBinding
+               0u,             // dstArrayElement
+               1u,
+               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+               (const VkDescriptorImageInfo*)DE_NULL,
+               &bufferInfo,
+               (const VkBufferView*)DE_NULL
+       };
+
+
+       vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL);
+
+       // Storage for output varying data.
+       std::vector<deUint32>   outputs         (NUM_ELEMENTS);
+       std::vector<void*>              outputPtr       (NUM_ELEMENTS);
+
+       for (size_t i = 0; i < NUM_ELEMENTS; i++)
+       {
+               outputs[i] = 0xcdcdcdcd;
+               outputPtr[i] = &outputs[i];
+       }
+
+       UniquePtr<ShaderExecutor> executor(createExecutor(m_context, m_shaderType, m_shaderSpec, *extraResourcesLayout));
+       executor->execute(NUM_ELEMENTS, DE_NULL, &outputPtr[0], *extraResourcesSet);
+       buffer.invalidate();
+
+       tcu::ResultCollector resultCollector(log);
+
+       // Check the results of the atomic operation
+       if (m_sign)
+               checkOperation<deInt32>(original, *ptr, resultCollector);
+       else
+               checkOperation<deUint32>(original, *ptr, resultCollector);
+
+       return tcu::TestStatus(resultCollector.getResult(), resultCollector.getMessage());
+}
+
+class AtomicOperationCase : public TestCase
+{
+public:
+                                                       AtomicOperationCase             (tcu::TestContext&              testCtx,
+                                                                                                        const char*                    name,
+                                                                                                        const char*                    description,
+                                                                                                        glu::ShaderType                type,
+                                                                                                        bool                                   sign,
+                                                                                                        AtomicOperation                atomicOp);
+       virtual                                 ~AtomicOperationCase    (void);
+
+       virtual TestInstance*   createInstance                  (Context& ctx) const;
+       virtual void                    initPrograms                    (vk::SourceCollections& programCollection) const
+       {
+               generateSources(m_shaderType, m_shaderSpec, programCollection);
+       }
+
+private:
+
+       void                                    createShaderSpec();
+       ShaderSpec                              m_shaderSpec;
+       const glu::ShaderType   m_shaderType;
+       const bool                              m_sign;
+       const AtomicOperation   m_atomicOp;
+};
+
+AtomicOperationCase::AtomicOperationCase (tcu::TestContext&    testCtx,
+                                                                                 const char*           name,
+                                                                                 const char*           description,
+                                                                                 glu::ShaderType       shaderType,
+                                                                                 bool                          sign,
+                                                                                 AtomicOperation       atomicOp)
+       : TestCase                      (testCtx, name, description)
+       , m_shaderType          (shaderType)
+       , m_sign                        (sign)
+       , m_atomicOp            (atomicOp)
+{
+       createShaderSpec();
+       init();
+}
+
+AtomicOperationCase::~AtomicOperationCase (void)
+{
+}
+
+TestInstance* AtomicOperationCase::createInstance (Context& ctx) const
+{
+       return new AtomicOperationCaseInstance(ctx, m_shaderSpec, m_shaderType, m_sign, m_atomicOp);
+}
+
+void AtomicOperationCase::createShaderSpec (void)
+{
+       const tcu::StringTemplate shaderTemplateGlobal(
+               "layout (set = ${SETIDX}, binding = 0, std430) buffer AtomicBuffer\n"
+               "{\n"
+               "    highp int index;\n"
+               "    highp ${DATATYPE} inoutValues[${N}/2];\n"
+               "    highp ${DATATYPE} inputValues[${N}];\n"
+               "    highp ${DATATYPE} compareValues[${N}];\n"
+               "    highp ${DATATYPE} outputValues[${N}];\n"
+               "} buf;\n");
+
+       std::map<std::string, std::string> specializations;
+       specializations["DATATYPE"] = m_sign ? "int" : "uint";
+       specializations["ATOMICOP"] = atomicOp2Str(m_atomicOp);
+       specializations["SETIDX"] = de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX);
+       specializations["N"] = de::toString((int)NUM_ELEMENTS);
+       specializations["COMPARE_ARG"] = m_atomicOp == ATOMIC_OP_COMP_SWAP ? "buf.compareValues[idx], " : "";
+
+       const tcu::StringTemplate shaderTemplateSrc(
+               "int idx = atomicAdd(buf.index, 1);\n"
+               "buf.outputValues[idx] = ${ATOMICOP}(buf.inoutValues[idx % (${N}/2)], ${COMPARE_ARG}buf.inputValues[idx]);\n");
+
+       m_shaderSpec.outputs.push_back(Symbol("outData", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+       m_shaderSpec.globalDeclarations = shaderTemplateGlobal.specialize(specializations);
+       m_shaderSpec.source = shaderTemplateSrc.specialize(specializations);
+}
+
+void addAtomicOperationTests (tcu::TestCaseGroup* atomicOperationTestsGroup)
+{
+       tcu::TestContext& testCtx = atomicOperationTestsGroup->getTestContext();
+
+       static const struct
+       {
+               glu::ShaderType type;
+               const char*             name;
+       } shaderTypes[] =
+       {
+               { glu::SHADERTYPE_VERTEX,                                       "vertex"        },
+               { glu::SHADERTYPE_FRAGMENT,                                     "fragment"      },
+               { glu::SHADERTYPE_GEOMETRY,                                     "geometry"      },
+               { glu::SHADERTYPE_TESSELLATION_CONTROL,         "tess_ctrl"     },
+               { glu::SHADERTYPE_TESSELLATION_EVALUATION,      "tess_eval"     },
+               { glu::SHADERTYPE_COMPUTE,                                      "compute"       }
+       };
+
+       static const struct
+       {
+               bool                    value;
+               const char*             name;
+               const char*             description;
+       } dataSign[] =
+       {
+               { true,         "signed",       "Tests using signed data (int)"         },
+               { false,        "unsigned",     "Tests using unsigned data (uint)"      }
+       };
+
+       static const struct
+       {
+               AtomicOperation         value;
+               const char*                     name;
+       } atomicOp[] =
+       {
+               { ATOMIC_OP_EXCHANGE,   "exchange"      },
+               { ATOMIC_OP_COMP_SWAP,  "comp_swap"     },
+               { ATOMIC_OP_ADD,                "add"           },
+               { ATOMIC_OP_MIN,                "min"           },
+               { ATOMIC_OP_MAX,                "max"           },
+               { ATOMIC_OP_AND,                "and"           },
+               { ATOMIC_OP_OR,                 "or"            },
+               { ATOMIC_OP_XOR,                "xor"           }
+       };
+
+       for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(atomicOp); opNdx++)
+       {
+               for (int signNdx = 0; signNdx < DE_LENGTH_OF_ARRAY(dataSign); signNdx++)
+               {
+                       for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
+                       {
+                               const std::string description = std::string("Tests atomic operation ") + atomicOp2Str(atomicOp[opNdx].value) + std::string(".");
+                               std::string name = std::string(atomicOp[opNdx].name) + "_" + std::string(dataSign[signNdx].name) + "_" + std::string(shaderTypes[shaderTypeNdx].name);
+                               atomicOperationTestsGroup->addChild(new AtomicOperationCase(testCtx, name.c_str(), description.c_str(), shaderTypes[shaderTypeNdx].type, dataSign[signNdx].value, atomicOp[opNdx].value));
+                       }
+               }
+       }
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createAtomicOperationTests (tcu::TestContext& testCtx)
+{
+       return createTestGroup(testCtx, "atomic_operations", "Atomic Operation Tests", addAtomicOperationTests);
+}
+
+} // shaderexecutor
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktAtomicOperationTests.hpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktAtomicOperationTests.hpp
new file mode 100644 (file)
index 0000000..ca3c472
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _VKTATOMICOPERATIONTESTS_HPP
+#define _VKTATOMICOPERATIONTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2017 Google Inc.
+ *
+ * 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.
+ *
+ *//*!
+ * \file
+ * \brief Atomic operations (OpAtomic*) tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+tcu::TestCaseGroup*            createAtomicOperationTests      (tcu::TestContext& testCtx);
+
+} // shaderexecutor
+} // vkt
+
+#endif // _VKTATOMICOPERATIONTESTS_HPP
index 4614abe..ad0a145 100644 (file)
@@ -59,6 +59,7 @@
 #include "vktShaderRenderTextureGatherTests.hpp"
 #include "vktShaderBuiltinTests.hpp"
 #include "vktOpaqueTypeIndexingTests.hpp"
+#include "vktAtomicOperationTests.hpp"
 #include "vktUniformBlockTests.hpp"
 #include "vktDynamicStateTests.hpp"
 #include "vktSSBOLayoutTests.hpp"
@@ -355,6 +356,7 @@ void createGlslTests (tcu::TestCaseGroup* glslTests)
        // ShaderExecutor-based tests
        glslTests->addChild(shaderexecutor::createBuiltinTests                          (testCtx));
        glslTests->addChild(shaderexecutor::createOpaqueTypeIndexingTests       (testCtx));
+       glslTests->addChild(shaderexecutor::createAtomicOperationTests          (testCtx));
 }
 
 // TestPackage
index dab2918..9769c0d 100644 (file)
@@ -171975,6 +171975,102 @@ dEQP-VK.glsl.opaque_type_indexing.atomic_counter.dynamically_uniform_geometry
 dEQP-VK.glsl.opaque_type_indexing.atomic_counter.dynamically_uniform_tess_ctrl
 dEQP-VK.glsl.opaque_type_indexing.atomic_counter.dynamically_uniform_tess_eval
 dEQP-VK.glsl.opaque_type_indexing.atomic_counter.dynamically_uniform_compute
+dEQP-VK.glsl.atomic_operations.exchange_signed_vertex
+dEQP-VK.glsl.atomic_operations.exchange_signed_fragment
+dEQP-VK.glsl.atomic_operations.exchange_signed_geometry
+dEQP-VK.glsl.atomic_operations.exchange_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.exchange_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.exchange_signed_compute
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.exchange_unsigned_compute
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_vertex
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_fragment
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_geometry
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.comp_swap_signed_compute
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.comp_swap_unsigned_compute
+dEQP-VK.glsl.atomic_operations.add_signed_vertex
+dEQP-VK.glsl.atomic_operations.add_signed_fragment
+dEQP-VK.glsl.atomic_operations.add_signed_geometry
+dEQP-VK.glsl.atomic_operations.add_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.add_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.add_signed_compute
+dEQP-VK.glsl.atomic_operations.add_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.add_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.add_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.add_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.add_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.add_unsigned_compute
+dEQP-VK.glsl.atomic_operations.min_signed_vertex
+dEQP-VK.glsl.atomic_operations.min_signed_fragment
+dEQP-VK.glsl.atomic_operations.min_signed_geometry
+dEQP-VK.glsl.atomic_operations.min_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.min_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.min_signed_compute
+dEQP-VK.glsl.atomic_operations.min_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.min_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.min_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.min_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.min_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.min_unsigned_compute
+dEQP-VK.glsl.atomic_operations.max_signed_vertex
+dEQP-VK.glsl.atomic_operations.max_signed_fragment
+dEQP-VK.glsl.atomic_operations.max_signed_geometry
+dEQP-VK.glsl.atomic_operations.max_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.max_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.max_signed_compute
+dEQP-VK.glsl.atomic_operations.max_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.max_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.max_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.max_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.max_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.max_unsigned_compute
+dEQP-VK.glsl.atomic_operations.and_signed_vertex
+dEQP-VK.glsl.atomic_operations.and_signed_fragment
+dEQP-VK.glsl.atomic_operations.and_signed_geometry
+dEQP-VK.glsl.atomic_operations.and_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.and_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.and_signed_compute
+dEQP-VK.glsl.atomic_operations.and_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.and_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.and_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.and_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.and_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.and_unsigned_compute
+dEQP-VK.glsl.atomic_operations.or_signed_vertex
+dEQP-VK.glsl.atomic_operations.or_signed_fragment
+dEQP-VK.glsl.atomic_operations.or_signed_geometry
+dEQP-VK.glsl.atomic_operations.or_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.or_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.or_signed_compute
+dEQP-VK.glsl.atomic_operations.or_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.or_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.or_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.or_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.or_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.or_unsigned_compute
+dEQP-VK.glsl.atomic_operations.xor_signed_vertex
+dEQP-VK.glsl.atomic_operations.xor_signed_fragment
+dEQP-VK.glsl.atomic_operations.xor_signed_geometry
+dEQP-VK.glsl.atomic_operations.xor_signed_tess_ctrl
+dEQP-VK.glsl.atomic_operations.xor_signed_tess_eval
+dEQP-VK.glsl.atomic_operations.xor_signed_compute
+dEQP-VK.glsl.atomic_operations.xor_unsigned_vertex
+dEQP-VK.glsl.atomic_operations.xor_unsigned_fragment
+dEQP-VK.glsl.atomic_operations.xor_unsigned_geometry
+dEQP-VK.glsl.atomic_operations.xor_unsigned_tess_ctrl
+dEQP-VK.glsl.atomic_operations.xor_unsigned_tess_eval
+dEQP-VK.glsl.atomic_operations.xor_unsigned_compute
 dEQP-VK.renderpass.simple.color
 dEQP-VK.renderpass.simple.depth
 dEQP-VK.renderpass.simple.stencil