New SSBO corner case test
authorToni Salmivalli <toni.salmivalli@siru.fi>
Thu, 18 Feb 2021 12:52:07 +0000 (14:52 +0200)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Thu, 13 May 2021 17:59:12 +0000 (17:59 +0000)
Added a new SSBO corner case test based on a reported compiler crash on
a certain implementation.

New test:

dEQP-VK.ssbo.corner_case.long_shader_bitwise_and

Components: Vulkan

VK-GL-CTS issue: 2725

Change-Id: I8e1f730d073c20e4fa35863b608b0c6ce0adfce9

AndroidGen.mk
android/cts/master/vk-master-2021-03-01/ssbo.txt
android/cts/master/vk-master/ssbo.txt
external/vulkancts/modules/vulkan/ssbo/CMakeLists.txt
external/vulkancts/modules/vulkan/ssbo/vktSSBOCornerCase.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/ssbo/vktSSBOCornerCase.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/ssbo/vktSSBOLayoutTests.cpp
external/vulkancts/mustpass/master/vk-default/ssbo.txt

index 68811a3..09beb94 100644 (file)
@@ -421,6 +421,7 @@ LOCAL_SRC_FILES := \
        external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmVaryingNameTests.cpp \
        external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmVectorShuffleTests.cpp \
        external/vulkancts/modules/vulkan/spirv_assembly/vktSpvAsmWorkgroupMemoryTests.cpp \
+       external/vulkancts/modules/vulkan/ssbo/vktSSBOCornerCase.cpp \
        external/vulkancts/modules/vulkan/ssbo/vktSSBOLayoutCase.cpp \
        external/vulkancts/modules/vulkan/ssbo/vktSSBOLayoutTests.cpp \
        external/vulkancts/modules/vulkan/subgroups/vktSubgroupsArithmeticTests.cpp \
index baf4a65..bae78d6 100644 (file)
@@ -3954,3 +3954,4 @@ dEQP-VK.ssbo.phys.layout.multi_nested_struct.single_buffer.scalar_comp_access_st
 dEQP-VK.ssbo.phys.layout.multi_nested_struct.single_buffer.scalar_instance_array_store_cols
 dEQP-VK.ssbo.phys.layout.multi_nested_struct.single_buffer.scalar_instance_array_comp_access_store_cols
 dEQP-VK.ssbo.phys.layout.random.16bit.scalar.13
+dEQP-VK.ssbo.corner_case.long_shader_bitwise_and
index 2fcea1a..557f87e 100644 (file)
@@ -12156,3 +12156,4 @@ dEQP-VK.ssbo.phys.layout.random.8bit.descriptor_indexing.46
 dEQP-VK.ssbo.phys.layout.random.8bit.descriptor_indexing.47
 dEQP-VK.ssbo.phys.layout.random.8bit.descriptor_indexing.48
 dEQP-VK.ssbo.phys.layout.random.8bit.descriptor_indexing.49
+dEQP-VK.ssbo.corner_case.long_shader_bitwise_and
index 9b6db22..c7590e1 100644 (file)
@@ -7,6 +7,8 @@ set(DEQP_VK_SSBO_SRCS
        vktSSBOLayoutCase.hpp
        vktSSBOLayoutTests.cpp
        vktSSBOLayoutTests.hpp
+       vktSSBOCornerCase.cpp
+       vktSSBOCornerCase.hpp
 )
 
 set(DEQP_VK_SSBO_LIBS
diff --git a/external/vulkancts/modules/vulkan/ssbo/vktSSBOCornerCase.cpp b/external/vulkancts/modules/vulkan/ssbo/vktSSBOCornerCase.cpp
new file mode 100644 (file)
index 0000000..bd7f753
--- /dev/null
@@ -0,0 +1,342 @@
+/*------------------------------------------------------------------------
+* Vulkan Conformance Tests
+* ------------------------
+*
+* Copyright (c) 2021 The Khronos Group Inc.
+* Copyright (c) 2021 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.
+*
+*//*!
+* \file
+* \brief SSBO corner case tests.
+*//*--------------------------------------------------------------------*/
+#include "deRandom.hpp"
+
+#include "vktSSBOCornerCase.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkRefUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkCmdUtil.hpp"
+
+#include <string>
+
+namespace vkt
+{
+namespace ssbo
+{
+       using std::string;
+       using std::vector;
+
+namespace
+{
+class CornerCase : public TestCase
+{
+public:
+                                                               CornerCase                      (tcu::TestContext &testCtx, const char *name, const char *description)
+       : TestCase                                                                              (testCtx, name, description)
+       {
+               init();
+       }
+       virtual void                            delayedInit                     (void);
+       virtual void                            initPrograms            (vk::SourceCollections &programCollection) const;
+       virtual TestInstance*           createInstance          (Context &context) const;
+
+protected:
+       string                                          m_computeShaderSrc;
+       const int                                       m_testSize                      = 589; // This is the minimum value of the variable that causes a crash.
+};
+
+string useCornerCaseShader (int loopCount)
+{
+       std::ostringstream src;
+       de::Random rnd(1);
+
+       src <<
+               "#version 310 es\n"
+               "#extension GL_EXT_buffer_reference : enable\n"
+               "layout(std430, buffer_reference) buffer BlockA\n"
+               "{\n"
+               " highp ivec4 a[];\n"
+               "};\n"
+               // ac_numIrrelevant is not used for anything, but is needed so that compiler doesn't optimize everything out.
+               "layout(std140, binding = 0) buffer AcBlock { highp uint ac_numIrrelevant; };\n"
+               "\n"
+               "layout (push_constant, std430) uniform PC {\n"
+               " BlockA blockA;\n"
+               "};\n"
+               "\n"
+               "bool compare_ivec4(highp ivec4 a, highp ivec4 b) { return a == b; }\n"
+               "\n"
+               "void main (void)\n"
+               "{\n"
+               " int allOk = int(true);\n";
+
+       for (int i = 0; i < loopCount; i++)
+       {
+               src << " allOk = allOk & int(compare_ivec4((blockA.a[" << i << "]), ivec4("
+                       << rnd.getInt(-9,9) << ", "
+                       << rnd.getInt(-9,9) << ", "
+                       << rnd.getInt(-9,9) << ", "
+                       << rnd.getInt(-9,9) << ")));\n";
+       }
+
+       src <<
+               " if (allOk != int(false))\n"
+               " {\n"
+               "  ac_numIrrelevant++;\n"
+               " }\n"
+               "}\n";
+
+       return src.str();
+}
+
+struct Buffer
+{
+       deUint32        buffer;
+       int                     size;
+
+       Buffer          (deUint32 buffer_, int size_)   : buffer(buffer_), size(size_) {}
+       Buffer          (void)                                                  : buffer(0), size(0) {}
+};
+
+de::MovePtr<vk::Allocation> allocateAndBindMemory (Context &context, vk::VkBuffer buffer, vk::MemoryRequirement memReqs)
+{
+       const vk::DeviceInterface               &vkd    = context.getDeviceInterface();
+       const vk::VkMemoryRequirements  bufReqs = vk::getBufferMemoryRequirements(vkd, context.getDevice(), buffer);
+       de::MovePtr<vk::Allocation>             memory  = context.getDefaultAllocator().allocate(bufReqs, memReqs);
+
+       vkd.bindBufferMemory(context.getDevice(), buffer, memory->getMemory(), memory->getOffset());
+
+       return memory;
+}
+
+vk::Move<vk::VkBuffer> createBuffer (Context &context, vk::VkDeviceSize bufferSize, vk::VkBufferUsageFlags usageFlags)
+{
+       const vk::VkDevice                      vkDevice                        = context.getDevice();
+       const vk::DeviceInterface       &vk                                     = context.getDeviceInterface();
+       const deUint32                          queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
+
+       const vk::VkBufferCreateInfo bufferInfo =
+       {
+               vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
+               DE_NULL,                                                                        // const void*                  pNext;
+               0u,                                                                                     // VkBufferCreateFlags  flags;
+               bufferSize,                                                                     // VkDeviceSize                 size;
+               usageFlags,                                                                     // VkBufferUsageFlags   usage;
+               vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
+               1u,                                                                                     // deUint32                             queueFamilyCount;
+               &queueFamilyIndex                                                       // const deUint32*              pQueueFamilyIndices;
+       };
+
+       return vk::createBuffer(vk, vkDevice, &bufferInfo);
+}
+class SSBOCornerCaseInstance : public TestInstance
+{
+public:
+                                                               SSBOCornerCaseInstance  (Context& context, int testSize);
+       virtual                                         ~SSBOCornerCaseInstance (void);
+       virtual tcu::TestStatus         iterate                                 (void);
+
+private:
+       int                                                     m_testSize;
+};
+SSBOCornerCaseInstance::SSBOCornerCaseInstance (Context& context, int testSize)
+       : TestInstance  (context)
+       , m_testSize    (testSize)
+{
+}
+SSBOCornerCaseInstance::~SSBOCornerCaseInstance (void)
+{
+}
+
+tcu::TestStatus SSBOCornerCaseInstance::iterate (void)
+{
+       const vk::DeviceInterface&              vk                                      = m_context.getDeviceInterface();
+       const vk::VkDevice                              device                          = m_context.getDevice();
+       const vk::VkQueue                               queue                           = m_context.getUniversalQueue();
+       const deUint32                                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+
+       vk::Move<vk::VkBuffer>                  buffer;
+       de::MovePtr<vk::Allocation>             alloc;
+
+       // Create descriptor set
+       const deUint32                                  acBufferSize            = 4;
+       vk::Move<vk::VkBuffer>                  acBuffer                        (createBuffer(m_context, acBufferSize, vk:: VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
+       de::UniquePtr<vk::Allocation>   acBufferAlloc           (allocateAndBindMemory(m_context, *acBuffer, vk::MemoryRequirement::HostVisible));
+
+       deMemset(acBufferAlloc->getHostPtr(), 0, acBufferSize);
+       flushMappedMemoryRange(vk, device, acBufferAlloc->getMemory(), acBufferAlloc->getOffset(), acBufferSize);
+
+       vk::DescriptorSetLayoutBuilder  setLayoutBuilder;
+       vk::DescriptorPoolBuilder               poolBuilder;
+
+       setLayoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
+       poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2);
+
+       const vk::Unique<vk::VkDescriptorSetLayout>     descriptorSetLayout     (setLayoutBuilder.build(vk, device));
+       const vk::Unique<vk::VkDescriptorPool>          descriptorPool          (poolBuilder.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
+
+       const vk::VkDescriptorSetAllocateInfo           allocInfo                       =
+       {
+               vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+               DE_NULL,
+               *descriptorPool,
+               1u,
+               &descriptorSetLayout.get(),
+       };
+
+       const vk::Unique<vk::VkDescriptorSet>   descriptorSet   (allocateDescriptorSet(vk, device, &allocInfo));
+       const vk::VkDescriptorBufferInfo                descriptorInfo  = makeDescriptorBufferInfo(*acBuffer, 0ull, acBufferSize);
+
+       vk::DescriptorSetUpdateBuilder                  setUpdateBuilder;
+       vk::VkDescriptorBufferInfo                              descriptor;
+
+       setUpdateBuilder
+                       .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo);
+
+       vk::VkFlags usageFlags          =       vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | vk::VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+       bool memoryDeviceAddress        =       false;
+
+       if (m_context.isDeviceFunctionalitySupported("VK_KHR_buffer_device_address"))
+               memoryDeviceAddress = true;
+
+       // Upload base buffers
+       const int bufferSize            =       64 * m_testSize;
+       {
+               vk::VkPhysicalDeviceProperties properties;
+               m_context.getInstanceInterface().getPhysicalDeviceProperties(m_context.getPhysicalDevice(), &properties);
+
+               DE_ASSERT(bufferSize > 0);
+
+               buffer          = createBuffer(m_context, bufferSize, usageFlags);
+               alloc           = allocateAndBindMemory(m_context, *buffer, vk::MemoryRequirement::HostVisible | (memoryDeviceAddress ? vk::MemoryRequirement::DeviceAddress : vk::MemoryRequirement::Any));
+               descriptor      = makeDescriptorBufferInfo(*buffer, 0, bufferSize);
+       }
+
+       // Query the buffer device address and push them via push constants
+       const bool useKHR = m_context.isDeviceFunctionalitySupported("VK_KHR_buffer_device_address");
+
+       vk::VkBufferDeviceAddressInfo info =
+       {
+               vk::VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,       // VkStructureType      sType;
+               DE_NULL,                                                                                        // const void*          pNext;
+               0,                                                                                                      // VkBuffer                     buffer
+       };
+
+       info.buffer = descriptor.buffer;
+       vk::VkDeviceAddress     addr;
+       if (useKHR)
+               addr = vk.getBufferDeviceAddress(device, &info);
+       else
+               addr = vk.getBufferDeviceAddressEXT(device, &info);
+
+       setUpdateBuilder.update(vk, device);
+
+       const vk::VkPushConstantRange pushConstRange =
+       {
+               vk::VK_SHADER_STAGE_COMPUTE_BIT,                // VkShaderStageFlags   stageFlags
+               0,                                                                              // deUint32                             offset
+               (deUint32)(sizeof(vk::VkDeviceAddress)) // deUint32                             size
+       };
+
+       // Must fit in spec min max
+       DE_ASSERT(pushConstRange.size <= 128);
+
+       const vk::VkPipelineLayoutCreateInfo            pipelineLayoutParams            =
+       {
+       vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,                      // VkStructureType                                      sType;
+       DE_NULL,                                                                                                        // const void*                                          pNext;
+       (vk::VkPipelineLayoutCreateFlags)0,
+       1u,                                                                                                                     // deUint32                                                     descriptorSetCount;
+       &*descriptorSetLayout,                                                                          // const VkDescriptorSetLayout*         pSetLayouts;
+       1u,                                                                                                                     // deUint32                                                     pushConstantRangeCount;
+       &pushConstRange,                                                                                        // const VkPushConstantRange*           pPushConstantRanges;
+       };
+       vk::Move<vk::VkPipelineLayout>  pipelineLayout  (createPipelineLayout(vk, device, &pipelineLayoutParams));
+
+       vk::Move<vk::VkShaderModule>    shaderModule    (createShaderModule(vk, device, m_context.getBinaryCollection().get("compute"), 0));
+       const vk::VkPipelineShaderStageCreateInfo       pipelineShaderStageParams       =
+       {
+               vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,// VkStructureType                                      sType;
+               DE_NULL,                                                                                                // const void*                                          pNext;
+               (vk::VkPipelineShaderStageCreateFlags)0,
+               vk::VK_SHADER_STAGE_COMPUTE_BIT,                                                // VkShaderStage                                        stage;
+               *shaderModule,                                                                                  // VkShader                                                     shader;
+               "main",                                                                                                 //
+               DE_NULL,                                                                                                // const VkSpecializationInfo*          pSpecializationInfo;
+       };
+       const vk::VkComputePipelineCreateInfo           pipelineCreateInfo                      =
+       {
+               vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,             // VkStructureType                                      sType;
+               DE_NULL,                                                                                                // const void*                                          pNext;
+               0,                                                                                                              // VkPipelineCreateFlags                        flags;
+               pipelineShaderStageParams,                                                              // VkPipelineShaderStageCreateInfo      stage;
+               *pipelineLayout,                                                                                // VkPipelineLayout                                     layout;
+               DE_NULL,                                                                                                // VkPipeline                                           basePipelineHandle;
+               0,                                                                                                              // deInt32                                                      basePipelineIndex;
+       };
+       vk::Move<vk::VkPipeline>                pipeline        (createComputePipeline(vk, device, DE_NULL, &pipelineCreateInfo));
+
+       vk::Move<vk::VkCommandPool>             cmdPool         (createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
+       vk::Move<vk::VkCommandBuffer>   cmdBuffer       (allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
+
+       beginCommandBuffer(vk, *cmdBuffer, 0u);
+
+       vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
+
+       vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, vk::VK_SHADER_STAGE_COMPUTE_BIT,0, (deUint32)(sizeof(addr)), &addr);
+
+       vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
+
+       vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
+
+       endCommandBuffer(vk, *cmdBuffer);
+
+       submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
+
+       // Test always passes if it doesn't cause a crash.
+       return tcu::TestStatus::pass("Test did not cause a crash");
+}
+
+void CornerCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       DE_ASSERT(!m_computeShaderSrc.empty());
+
+       programCollection.glslSources.add("compute") << glu::ComputeSource(m_computeShaderSrc);
+}
+
+TestInstance* CornerCase::createInstance (Context& context) const
+{
+       if (!context.isBufferDeviceAddressSupported())
+               TCU_THROW(NotSupportedError, "Physical storage buffer pointers not supported");
+       return new SSBOCornerCaseInstance(context, m_testSize);
+}
+
+void CornerCase::delayedInit (void)
+{
+       m_computeShaderSrc = useCornerCaseShader(m_testSize);
+}
+} // anonymous
+
+tcu::TestCaseGroup* createSSBOCornerCaseTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> cornerCaseGroup (new tcu::TestCaseGroup(testCtx, "corner_case", "Corner cases"));
+       cornerCaseGroup->addChild(new CornerCase(testCtx, "long_shader_bitwise_and", ""));
+       return cornerCaseGroup.release();
+}
+} // ssbo
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/ssbo/vktSSBOCornerCase.hpp b/external/vulkancts/modules/vulkan/ssbo/vktSSBOCornerCase.hpp
new file mode 100644 (file)
index 0000000..8f4be8f
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _VKTSSBOCORNERCASE_HPP
+#define _VKTSSBOCORNERCASE_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2021 The Khronos Group Inc.
+ * Copyright (c) 2021 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.
+ *
+ *//*!
+ * \file
+ * \brief SSBO corner case tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+       namespace ssbo
+       {
+               tcu::TestCaseGroup* createSSBOCornerCaseTests (tcu::TestContext& testCtx);
+       } // ssbo
+} // vkt
+
+#endif // _VKTSSBOCORNERCASE_HPP
index 3624389..eb95f04 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "vktSSBOLayoutTests.hpp"
 #include "vktSSBOLayoutCase.hpp"
+#include "vktSSBOCornerCase.hpp"
 
 #include "deUniquePtr.hpp"
 #include "tcuCommandLine.hpp"
@@ -1822,6 +1823,8 @@ tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
        physGroup->addChild(new SSBOLayoutTests(testCtx, true, false));
        ssboTestGroup->addChild(physGroup.release());
 
+       ssboTestGroup->addChild(createSSBOCornerCaseTests(testCtx));
+
        return ssboTestGroup.release();
 }
 
index 2fcea1a..557f87e 100644 (file)
@@ -12156,3 +12156,4 @@ dEQP-VK.ssbo.phys.layout.random.8bit.descriptor_indexing.46
 dEQP-VK.ssbo.phys.layout.random.8bit.descriptor_indexing.47
 dEQP-VK.ssbo.phys.layout.random.8bit.descriptor_indexing.48
 dEQP-VK.ssbo.phys.layout.random.8bit.descriptor_indexing.49
+dEQP-VK.ssbo.corner_case.long_shader_bitwise_and