1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2016 Imagination Technologies Ltd.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 * \brief Robust buffer access tests for uniform/storage buffers and
23 * uniform/storage texel buffers.
24 *//*--------------------------------------------------------------------*/
26 #include "vktRobustnessBufferAccessTests.hpp"
27 #include "vktRobustnessUtil.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vkBuilderUtil.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkPrograms.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkDeviceUtil.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "tcuTestLog.hpp"
51 SHADER_TYPE_MATRIX_COPY,
52 SHADER_TYPE_VECTOR_COPY,
53 SHADER_TYPE_SCALAR_COPY,
54 SHADER_TYPE_TEXEL_COPY,
61 BUFFER_ACCESS_TYPE_READ,
62 BUFFER_ACCESS_TYPE_READ_FROM_STORAGE,
63 BUFFER_ACCESS_TYPE_WRITE,
66 static VkDeviceSize min (VkDeviceSize a, VkDeviceSize b)
68 return (a < b) ? a : b;
71 class RobustBufferAccessTest : public vkt::TestCase
74 static const deUint32 s_testArraySize;
75 static const deUint32 s_numberOfBytesAccessed;
77 RobustBufferAccessTest (tcu::TestContext& testContext,
78 const std::string& name,
79 const std::string& description,
80 VkShaderStageFlags shaderStage,
81 ShaderType shaderType,
82 VkFormat bufferFormat,
83 bool testPipelineRobustness);
85 virtual ~RobustBufferAccessTest (void) {}
87 virtual void checkSupport (Context& context) const;
90 static void genBufferShaderAccess (ShaderType shaderType,
91 VkFormat bufferFormat,
93 std::ostringstream& bufferDefinition,
94 std::ostringstream& bufferUse);
96 static void genTexelBufferShaderAccess (VkFormat bufferFormat,
97 std::ostringstream& bufferDefinition,
98 std::ostringstream& bufferUse,
99 bool readFromStorage);
102 bool is64BitsTest (void) const;
103 bool isVertexTest (void) const;
104 bool isFragmentTest (void) const;
106 static void initBufferAccessPrograms (SourceCollections& programCollection,
107 VkShaderStageFlags shaderStage,
108 ShaderType shaderType,
109 VkFormat bufferFormat,
110 bool readFromStorage);
112 const VkShaderStageFlags m_shaderStage;
113 const ShaderType m_shaderType;
114 const VkFormat m_bufferFormat;
115 const bool m_testPipelineRobustness;
118 class RobustBufferReadTest : public RobustBufferAccessTest
121 RobustBufferReadTest (tcu::TestContext& testContext,
122 const std::string& name,
123 const std::string& description,
124 VkShaderStageFlags shaderStage,
125 ShaderType shaderType,
126 VkFormat bufferFormat,
127 bool testPipelineRobustness,
128 VkDeviceSize readAccessRange,
129 bool readFromStorage,
130 bool accessOutOfBackingMemory);
132 virtual ~RobustBufferReadTest (void) {}
134 virtual void initPrograms (SourceCollections& programCollection) const;
135 virtual TestInstance* createInstance (Context& context) const;
138 const bool m_readFromStorage;
139 const VkDeviceSize m_readAccessRange;
140 const bool m_accessOutOfBackingMemory;
143 class RobustBufferWriteTest : public RobustBufferAccessTest
146 RobustBufferWriteTest (tcu::TestContext& testContext,
147 const std::string& name,
148 const std::string& description,
149 VkShaderStageFlags shaderStage,
150 ShaderType shaderType,
151 VkFormat bufferFormat,
152 bool testPipelineRobustness,
153 VkDeviceSize writeAccessRange,
154 bool accessOutOfBackingMemory);
156 virtual ~RobustBufferWriteTest (void) {}
158 virtual void initPrograms (SourceCollections& programCollection) const;
159 virtual TestInstance* createInstance (Context& context) const;
162 const VkDeviceSize m_writeAccessRange;
163 const bool m_accessOutOfBackingMemory;
166 class BufferAccessInstance : public vkt::TestInstance
169 BufferAccessInstance (Context& context,
170 Move<VkDevice> device,
171 #ifndef CTS_USES_VULKANSC
172 de::MovePtr<vk::DeviceDriver> deviceDriver,
174 de::MovePtr<vk::DeviceDriverSC,vk::DeinitDeviceDeleter> deviceDriver,
175 #endif // CTS_USES_VULKANSC
176 ShaderType shaderType,
177 VkShaderStageFlags shaderStage,
178 VkFormat bufferFormat,
179 BufferAccessType bufferAccessType,
180 VkDeviceSize inBufferAccessRange,
181 VkDeviceSize outBufferAccessRange,
182 bool accessOutOfBackingMemory,
183 bool testPipelineRobustness);
185 virtual ~BufferAccessInstance (void);
187 virtual tcu::TestStatus iterate (void);
189 virtual bool verifyResult (void);
192 bool isExpectedValueFromInBuffer (VkDeviceSize offsetInBytes, const void* valuePtr, VkDeviceSize valueSize);
193 bool isOutBufferValueUnchanged (VkDeviceSize offsetInBytes, VkDeviceSize valueSize);
196 Move<VkDevice> m_device;
197 #ifndef CTS_USES_VULKANSC
198 de::MovePtr<vk::DeviceDriver> m_deviceDriver;
200 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> m_deviceDriver;
201 #endif // CTS_USES_VULKANSC
202 de::MovePtr<TestEnvironment> m_testEnvironment;
204 const ShaderType m_shaderType;
205 const VkShaderStageFlags m_shaderStage;
207 const VkFormat m_bufferFormat;
208 const BufferAccessType m_bufferAccessType;
210 const VkDeviceSize m_inBufferAccessRange;
211 Move<VkBuffer> m_inBuffer;
212 de::MovePtr<Allocation> m_inBufferAlloc;
213 VkDeviceSize m_inBufferAllocSize;
214 VkDeviceSize m_inBufferMaxAccessRange;
216 const VkDeviceSize m_outBufferAccessRange;
217 Move<VkBuffer> m_outBuffer;
218 de::MovePtr<Allocation> m_outBufferAlloc;
219 VkDeviceSize m_outBufferAllocSize;
220 VkDeviceSize m_outBufferMaxAccessRange;
222 Move<VkBuffer> m_indicesBuffer;
223 de::MovePtr<Allocation> m_indicesBufferAlloc;
225 Move<VkDescriptorPool> m_descriptorPool;
226 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
227 Move<VkDescriptorSet> m_descriptorSet;
229 Move<VkFence> m_fence;
232 // Used when m_shaderStage == VK_SHADER_STAGE_VERTEX_BIT
233 Move<VkBuffer> m_vertexBuffer;
234 de::MovePtr<Allocation> m_vertexBufferAlloc;
236 // Used when m_shaderType == SHADER_TYPE_TEXEL_COPY
237 Move<VkBufferView> m_inTexelBufferView;
238 Move<VkBufferView> m_outTexelBufferView;
240 const bool m_accessOutOfBackingMemory;
241 const bool m_testPipelineRobustness;
244 class BufferReadInstance: public BufferAccessInstance
247 BufferReadInstance (Context& context,
248 Move<VkDevice> device,
249 #ifndef CTS_USES_VULKANSC
250 de::MovePtr<vk::DeviceDriver> deviceDriver,
252 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
253 #endif // CTS_USES_VULKANSC
254 ShaderType shaderType,
255 VkShaderStageFlags shaderStage,
256 VkFormat bufferFormat,
257 bool readFromStorage,
258 VkDeviceSize inBufferAccessRange,
259 bool accessOutOfBackingMemory,
260 bool testPipelineRobustness);
262 virtual ~BufferReadInstance (void) {}
267 class BufferWriteInstance: public BufferAccessInstance
270 BufferWriteInstance (Context& context,
271 Move<VkDevice> device,
272 #ifndef CTS_USES_VULKANSC
273 de::MovePtr<vk::DeviceDriver> deviceDriver,
275 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
276 #endif // CTS_USES_VULKANSC
277 ShaderType shaderType,
278 VkShaderStageFlags shaderStage,
279 VkFormat bufferFormat,
280 VkDeviceSize writeBufferAccessRange,
281 bool accessOutOfBackingMemory,
282 bool testPipelineRobustness);
284 virtual ~BufferWriteInstance (void) {}
287 // RobustBufferAccessTest
289 const deUint32 RobustBufferAccessTest::s_testArraySize = 128; // Fit within minimum required maxUniformBufferRange
290 const deUint32 RobustBufferAccessTest::s_numberOfBytesAccessed = (deUint32)(16 * sizeof(float)); // size of mat4
292 RobustBufferAccessTest::RobustBufferAccessTest (tcu::TestContext& testContext,
293 const std::string& name,
294 const std::string& description,
295 VkShaderStageFlags shaderStage,
296 ShaderType shaderType,
297 VkFormat bufferFormat,
298 bool testPipelineRobustness)
299 : vkt::TestCase (testContext, name, description)
300 , m_shaderStage (shaderStage)
301 , m_shaderType (shaderType)
302 , m_bufferFormat (bufferFormat)
303 , m_testPipelineRobustness (testPipelineRobustness)
305 DE_ASSERT(m_shaderStage == VK_SHADER_STAGE_VERTEX_BIT || m_shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT || m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT);
308 void RobustBufferAccessTest::checkSupport(Context& context) const
310 if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getDeviceFeatures().robustBufferAccess)
311 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: robustBufferAccess not supported by this implementation");
314 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_INT64);
317 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
319 if (isFragmentTest())
320 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
323 void RobustBufferAccessTest::genBufferShaderAccess (ShaderType shaderType,
324 VkFormat bufferFormat,
325 bool readFromStorage,
326 std::ostringstream& bufferDefinition,
327 std::ostringstream& bufferUse)
329 if (isFloatFormat(bufferFormat))
332 "layout(binding = 0, " << (readFromStorage ? "std430" : "std140") << ") " << (readFromStorage ? "buffer" : "uniform") << " InBuffer\n"
334 " mat4 inMatrix[" << s_testArraySize << "];\n"
338 "layout(binding = 1, std430) buffer OutBuffer\n"
340 " mat4 outMatrix[" << s_testArraySize << "];\n"
344 "layout(binding = 2, std140) uniform Indices\n"
352 case SHADER_TYPE_MATRIX_COPY:
354 " mat4 tmp = inMatrix[inIndex];\n"
355 " outMatrix[outIndex] = tmp;\n";
358 case SHADER_TYPE_VECTOR_COPY:
360 " outMatrix[outIndex][0] = inMatrix[inIndex][0];\n"
361 " outMatrix[outIndex][1] = inMatrix[inIndex][1];\n"
362 " outMatrix[outIndex][2] = inMatrix[inIndex][2];\n"
363 " outMatrix[outIndex][3] = inMatrix[inIndex][3];\n";
366 case SHADER_TYPE_SCALAR_COPY:
368 " outMatrix[outIndex][0][0] = inMatrix[inIndex][0][0];\n"
369 " outMatrix[outIndex][0][1] = inMatrix[inIndex][0][1];\n"
370 " outMatrix[outIndex][0][2] = inMatrix[inIndex][0][2];\n"
371 " outMatrix[outIndex][0][3] = inMatrix[inIndex][0][3];\n"
373 " outMatrix[outIndex][1][0] = inMatrix[inIndex][1][0];\n"
374 " outMatrix[outIndex][1][1] = inMatrix[inIndex][1][1];\n"
375 " outMatrix[outIndex][1][2] = inMatrix[inIndex][1][2];\n"
376 " outMatrix[outIndex][1][3] = inMatrix[inIndex][1][3];\n"
378 " outMatrix[outIndex][2][0] = inMatrix[inIndex][2][0];\n"
379 " outMatrix[outIndex][2][1] = inMatrix[inIndex][2][1];\n"
380 " outMatrix[outIndex][2][2] = inMatrix[inIndex][2][2];\n"
381 " outMatrix[outIndex][2][3] = inMatrix[inIndex][2][3];\n"
383 " outMatrix[outIndex][3][0] = inMatrix[inIndex][3][0];\n"
384 " outMatrix[outIndex][3][1] = inMatrix[inIndex][3][1];\n"
385 " outMatrix[outIndex][3][2] = inMatrix[inIndex][3][2];\n"
386 " outMatrix[outIndex][3][3] = inMatrix[inIndex][3][3];\n";
395 std::string typePrefixStr;
397 if (isUintFormat(bufferFormat))
401 else if (isIntFormat(bufferFormat))
410 typePrefixStr += (bufferFormat == vk::VK_FORMAT_R64_UINT || bufferFormat == vk::VK_FORMAT_R64_SINT) ?
414 "layout(binding = 0, " << (readFromStorage ? "std430" : "std140") << ") " << (readFromStorage ? "buffer readonly" : "uniform") << " InBuffer\n"
416 " " << typePrefixStr << "vec4 inVecs[" << s_testArraySize << "][4];\n"
420 "layout(binding = 1, std430) buffer OutBuffer\n"
422 " " << typePrefixStr << "vec4 outVecs[" << s_testArraySize << "][4];\n"
426 "layout(binding = 2, std140) uniform Indices\n"
434 case SHADER_TYPE_MATRIX_COPY:
435 // Shader type not supported for integer types.
439 case SHADER_TYPE_VECTOR_COPY:
441 " outVecs[outIndex][0] = inVecs[inIndex][0];\n"
442 " outVecs[outIndex][1] = inVecs[inIndex][1];\n"
443 " outVecs[outIndex][2] = inVecs[inIndex][2];\n"
444 " outVecs[outIndex][3] = inVecs[inIndex][3];\n";
447 case SHADER_TYPE_SCALAR_COPY:
449 " outVecs[outIndex][0][0] = inVecs[inIndex][0][0];\n"
450 " outVecs[outIndex][0][1] = inVecs[inIndex][0][1];\n"
451 " outVecs[outIndex][0][2] = inVecs[inIndex][0][2];\n"
452 " outVecs[outIndex][0][3] = inVecs[inIndex][0][3];\n"
454 " outVecs[outIndex][1][0] = inVecs[inIndex][1][0];\n"
455 " outVecs[outIndex][1][1] = inVecs[inIndex][1][1];\n"
456 " outVecs[outIndex][1][2] = inVecs[inIndex][1][2];\n"
457 " outVecs[outIndex][1][3] = inVecs[inIndex][1][3];\n"
459 " outVecs[outIndex][2][0] = inVecs[inIndex][2][0];\n"
460 " outVecs[outIndex][2][1] = inVecs[inIndex][2][1];\n"
461 " outVecs[outIndex][2][2] = inVecs[inIndex][2][2];\n"
462 " outVecs[outIndex][2][3] = inVecs[inIndex][2][3];\n"
464 " outVecs[outIndex][3][0] = inVecs[inIndex][3][0];\n"
465 " outVecs[outIndex][3][1] = inVecs[inIndex][3][1];\n"
466 " outVecs[outIndex][3][2] = inVecs[inIndex][3][2];\n"
467 " outVecs[outIndex][3][3] = inVecs[inIndex][3][3];\n";
476 void RobustBufferAccessTest::genTexelBufferShaderAccess (VkFormat bufferFormat,
477 std::ostringstream& bufferDefinition,
478 std::ostringstream& bufferUse,
479 bool readFromStorage)
481 const char* layoutTypeStr;
482 const char* inTexelBufferTypeStr;
483 const char* outTexelBufferTypeStr;
484 const deUint32 texelSize = mapVkFormat(bufferFormat).getPixelSize();
486 if (isFloatFormat(bufferFormat))
488 layoutTypeStr = "rgba32f";
489 inTexelBufferTypeStr = readFromStorage ? "imageBuffer" : "textureBuffer";
490 outTexelBufferTypeStr = "imageBuffer";
492 else if (isUintFormat(bufferFormat))
494 layoutTypeStr = "rgba32ui";
495 inTexelBufferTypeStr = readFromStorage ? "uimageBuffer" : "utextureBuffer";
496 outTexelBufferTypeStr = "uimageBuffer";
498 else if (isIntFormat(bufferFormat))
500 layoutTypeStr = "rgba32i";
501 inTexelBufferTypeStr = readFromStorage ? "iimageBuffer" : "itextureBuffer";
502 outTexelBufferTypeStr = "iimageBuffer";
504 else if (bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
506 layoutTypeStr = "rgb10_a2";
507 inTexelBufferTypeStr = readFromStorage ? "imageBuffer" : "textureBuffer"; outTexelBufferTypeStr = "imageBuffer";
511 TCU_THROW(NotSupportedError, (std::string("Unsupported format: ") + getFormatName(bufferFormat)).c_str());
514 bufferDefinition << "layout(set = 0, binding = 0" << ((readFromStorage) ? (std::string(", ") + layoutTypeStr) : "") << ") uniform highp "
515 << ((readFromStorage) ? "readonly " : "") << inTexelBufferTypeStr << " inImage;\n";
517 bufferDefinition << "layout(set = 0, binding = 1, " << layoutTypeStr << ") uniform highp writeonly " << outTexelBufferTypeStr << " outImage;\n";
520 "layout(binding = 2, std140) uniform Offsets\n"
526 bufferUse << " for (int i = 0; i < " << (s_numberOfBytesAccessed / texelSize) << "; i++)\n"
528 << " imageStore(outImage, outOffset + i, " << (readFromStorage ? "imageLoad" : "texelFetch") << "(inImage, inOffset + i));\n"
532 bool RobustBufferAccessTest::is64BitsTest (void) const
534 return (m_bufferFormat == VK_FORMAT_R64_SINT || m_bufferFormat == VK_FORMAT_R64_UINT);
537 bool RobustBufferAccessTest::isVertexTest (void) const
539 return ((m_shaderStage & VK_SHADER_STAGE_VERTEX_BIT) != 0u);
542 bool RobustBufferAccessTest::isFragmentTest (void) const
544 return ((m_shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0u);
547 void RobustBufferAccessTest::initBufferAccessPrograms (SourceCollections& programCollection,
548 VkShaderStageFlags shaderStage,
549 ShaderType shaderType,
550 VkFormat bufferFormat,
551 bool readFromStorage)
553 std::ostringstream bufferDefinition;
554 std::ostringstream bufferUse;
555 std::string extensions;
557 if (bufferFormat == vk::VK_FORMAT_R64_UINT || bufferFormat == vk::VK_FORMAT_R64_SINT)
559 extensions = "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n";
562 if (shaderType != SHADER_TYPE_TEXEL_COPY)
564 genBufferShaderAccess(shaderType, bufferFormat, readFromStorage, bufferDefinition, bufferUse);
567 if (shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
569 std::ostringstream computeShaderSource;
571 if (shaderType == SHADER_TYPE_TEXEL_COPY)
572 genTexelBufferShaderAccess(bufferFormat, bufferDefinition, bufferUse, readFromStorage);
574 computeShaderSource <<
576 "#extension GL_EXT_texture_buffer : require\n"
578 "precision highp float;\n"
579 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
580 << bufferDefinition.str() <<
583 << bufferUse.str() <<
586 programCollection.glslSources.add("compute") << glu::ComputeSource(computeShaderSource.str());
590 std::ostringstream vertexShaderSource;
591 std::ostringstream fragmentShaderSource;
593 if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
595 if (shaderType == SHADER_TYPE_TEXEL_COPY)
596 genTexelBufferShaderAccess(bufferFormat, bufferDefinition, bufferUse, readFromStorage);
598 vertexShaderSource <<
600 "#extension GL_EXT_texture_buffer : require\n"
602 "precision highp float;\n"
603 "layout(location = 0) in vec4 position;\n\n"
604 << bufferDefinition.str() << "\n"
605 "out gl_PerVertex {\n"
606 " vec4 gl_Position;\n"
610 << bufferUse.str() <<
611 " gl_Position = position;\n"
616 vertexShaderSource <<
618 "precision highp float;\n"
619 "layout(location = 0) in vec4 position;\n\n"
620 "out gl_PerVertex {\n"
621 " vec4 gl_Position;\n"
625 " gl_Position = position;\n"
629 programCollection.glslSources.add("vertex") << glu::VertexSource(vertexShaderSource.str());
631 if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
633 if (shaderType == SHADER_TYPE_TEXEL_COPY)
634 genTexelBufferShaderAccess(bufferFormat, bufferDefinition, bufferUse, readFromStorage);
636 fragmentShaderSource <<
638 "#extension GL_EXT_texture_buffer : require\n"
640 "precision highp float;\n"
641 "layout(location = 0) out vec4 fragColor;\n"
642 << bufferDefinition.str() <<
645 << bufferUse.str() <<
646 " fragColor = vec4(1.0);\n"
651 fragmentShaderSource <<
653 "precision highp float;\n"
654 "layout(location = 0) out vec4 fragColor;\n\n"
657 " fragColor = vec4(1.0);\n"
661 programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentShaderSource.str());
665 // RobustBufferReadTest
667 RobustBufferReadTest::RobustBufferReadTest (tcu::TestContext& testContext,
668 const std::string& name,
669 const std::string& description,
670 VkShaderStageFlags shaderStage,
671 ShaderType shaderType,
672 VkFormat bufferFormat,
673 bool testPipelineRobustness,
674 VkDeviceSize readAccessRange,
675 bool readFromStorage,
676 bool accessOutOfBackingMemory)
677 : RobustBufferAccessTest (testContext, name, description, shaderStage, shaderType, bufferFormat, testPipelineRobustness)
678 , m_readFromStorage (readFromStorage)
679 , m_readAccessRange (readAccessRange)
680 , m_accessOutOfBackingMemory (accessOutOfBackingMemory)
684 void RobustBufferReadTest::initPrograms (SourceCollections& programCollection) const
686 initBufferAccessPrograms(programCollection, m_shaderStage, m_shaderType, m_bufferFormat, m_readFromStorage);
689 TestInstance* RobustBufferReadTest::createInstance (Context& context) const
691 const bool is64BitsTest_ = is64BitsTest();
692 const bool isVertexTest_ = isVertexTest();
693 const bool isFragmentTest_ = isFragmentTest();
695 VkPhysicalDeviceFeatures2 features2 = initVulkanStructure();
697 if (!m_testPipelineRobustness)
698 features2.features.robustBufferAccess = VK_TRUE;
701 features2.features.shaderInt64 = VK_TRUE;
704 features2.features.vertexPipelineStoresAndAtomics = VK_TRUE;
707 features2.features.fragmentStoresAndAtomics = VK_TRUE;
709 #ifndef CTS_USES_VULKANSC
710 VkPhysicalDevicePipelineRobustnessFeaturesEXT pipelineRobustnessFeatures = initVulkanStructure();
711 if (m_testPipelineRobustness)
713 context.requireDeviceFunctionality("VK_EXT_pipeline_robustness");
715 pipelineRobustnessFeatures.pipelineRobustness = VK_TRUE;
717 pipelineRobustnessFeatures.pNext = features2.pNext;
718 features2.pNext = &pipelineRobustnessFeatures;
722 const bool useFeatures2 = (m_testPipelineRobustness || is64BitsTest_ || isVertexTest_ || isFragmentTest_);
724 Move<VkDevice> device = createRobustBufferAccessDevice(context, (useFeatures2 ? &features2 : nullptr));
725 #ifndef CTS_USES_VULKANSC
726 de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device));
728 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver = de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *device, context.getTestContext().getCommandLine(), context.getResourceInterface(), context.getDeviceVulkanSC10Properties(), context.getDeviceProperties()), vk::DeinitDeviceDeleter( context.getResourceInterface().get(), *device ));
729 #endif // CTS_USES_VULKANSC
731 return new BufferReadInstance(context, device, deviceDriver, m_shaderType, m_shaderStage, m_bufferFormat, m_readFromStorage, m_readAccessRange, m_accessOutOfBackingMemory, m_testPipelineRobustness);
734 // RobustBufferWriteTest
736 RobustBufferWriteTest::RobustBufferWriteTest (tcu::TestContext& testContext,
737 const std::string& name,
738 const std::string& description,
739 VkShaderStageFlags shaderStage,
740 ShaderType shaderType,
741 VkFormat bufferFormat,
742 bool testPipelineRobustness,
743 VkDeviceSize writeAccessRange,
744 bool accessOutOfBackingMemory)
746 : RobustBufferAccessTest (testContext, name, description, shaderStage, shaderType, bufferFormat, testPipelineRobustness)
747 , m_writeAccessRange (writeAccessRange)
748 , m_accessOutOfBackingMemory (accessOutOfBackingMemory)
752 void RobustBufferWriteTest::initPrograms (SourceCollections& programCollection) const
754 initBufferAccessPrograms(programCollection, m_shaderStage, m_shaderType, m_bufferFormat, false /* readFromStorage */);
757 TestInstance* RobustBufferWriteTest::createInstance (Context& context) const
759 const bool is64BitsTest_ = is64BitsTest();
760 const bool isVertexTest_ = isVertexTest();
761 const bool isFragmentTest_ = isFragmentTest();
763 VkPhysicalDeviceFeatures2 features2 = initVulkanStructure();
765 if (!m_testPipelineRobustness)
766 features2.features.robustBufferAccess = VK_TRUE;
769 features2.features.shaderInt64 = VK_TRUE;
772 features2.features.vertexPipelineStoresAndAtomics = VK_TRUE;
775 features2.features.fragmentStoresAndAtomics = VK_TRUE;
777 #ifndef CTS_USES_VULKANSC
778 VkPhysicalDevicePipelineRobustnessFeaturesEXT pipelineRobustnessFeatures = initVulkanStructure();
779 if (m_testPipelineRobustness)
781 context.requireDeviceFunctionality("VK_EXT_pipeline_robustness");
783 const auto& vki = context.getInstanceInterface();
784 const auto physicalDevice = context.getPhysicalDevice();
786 pipelineRobustnessFeatures.pNext = features2.pNext;
787 features2.pNext = &pipelineRobustnessFeatures;
789 vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
793 const bool useFeatures2 = (m_testPipelineRobustness || is64BitsTest_ || isVertexTest_ || isFragmentTest_);
795 Move<VkDevice> device = createRobustBufferAccessDevice(context, (useFeatures2 ? &features2 : nullptr));
796 #ifndef CTS_USES_VULKANSC
797 de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device));
799 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver = de::MovePtr<DeviceDriverSC,DeinitDeviceDeleter>(new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *device, context.getTestContext().getCommandLine(), context.getResourceInterface(), context.getDeviceVulkanSC10Properties(), context.getDeviceProperties()), DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
800 #endif // CTS_USES_VULKANSC
802 return new BufferWriteInstance(context, device, deviceDriver, m_shaderType, m_shaderStage, m_bufferFormat, m_writeAccessRange, m_accessOutOfBackingMemory, m_testPipelineRobustness);
805 // BufferAccessInstance
807 BufferAccessInstance::BufferAccessInstance (Context& context,
808 Move<VkDevice> device,
809 #ifndef CTS_USES_VULKANSC
810 de::MovePtr<vk::DeviceDriver> deviceDriver,
812 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
813 #endif // CTS_USES_VULKANSC
814 ShaderType shaderType,
815 VkShaderStageFlags shaderStage,
816 VkFormat bufferFormat,
817 BufferAccessType bufferAccessType,
818 VkDeviceSize inBufferAccessRange,
819 VkDeviceSize outBufferAccessRange,
820 bool accessOutOfBackingMemory,
821 bool testPipelineRobustness)
822 : vkt::TestInstance (context)
824 , m_deviceDriver (deviceDriver)
825 , m_shaderType (shaderType)
826 , m_shaderStage (shaderStage)
827 , m_bufferFormat (bufferFormat)
828 , m_bufferAccessType (bufferAccessType)
829 , m_inBufferAccessRange (inBufferAccessRange)
830 , m_outBufferAccessRange (outBufferAccessRange)
831 , m_accessOutOfBackingMemory (accessOutOfBackingMemory)
832 , m_testPipelineRobustness (testPipelineRobustness)
834 const DeviceInterface& vk = *m_deviceDriver;
835 const auto& vki = context.getInstanceInterface();
836 const auto instance = context.getInstance();
837 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
838 const bool isTexelAccess = !!(m_shaderType == SHADER_TYPE_TEXEL_COPY);
839 const bool readFromStorage = !!(m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE);
840 const VkPhysicalDevice physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine());
841 SimpleAllocator memAlloc (vk, *m_device, getPhysicalDeviceMemoryProperties(vki, physicalDevice));
842 tcu::TestLog& log = m_context.getTestContext().getLog();
844 DE_ASSERT(RobustBufferAccessTest::s_numberOfBytesAccessed % sizeof(deUint32) == 0);
845 DE_ASSERT(inBufferAccessRange <= RobustBufferAccessTest::s_numberOfBytesAccessed);
846 DE_ASSERT(outBufferAccessRange <= RobustBufferAccessTest::s_numberOfBytesAccessed);
848 if (m_bufferFormat == VK_FORMAT_R64_UINT || m_bufferFormat == VK_FORMAT_R64_SINT)
850 context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
853 // Check storage support
854 if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
856 if (!context.getDeviceFeatures().vertexPipelineStoresAndAtomics)
858 TCU_THROW(NotSupportedError, "Stores not supported in vertex stage");
861 else if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
863 if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
865 TCU_THROW(NotSupportedError, "Stores not supported in fragment stage");
869 // Check format support
871 VkFormatFeatureFlags requiredFormatFeatures = 0;
872 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(vki, physicalDevice, m_bufferFormat);
876 requiredFormatFeatures = VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
879 if ((formatProperties.bufferFeatures & requiredFormatFeatures) != requiredFormatFeatures)
881 TCU_THROW(NotSupportedError, (std::string("Format cannot be used in uniform and storage") + (isTexelAccess ? " texel" : "") + " buffers: "
882 + getFormatName(m_bufferFormat)).c_str());
886 // Create buffer to read data from
888 VkBufferUsageFlags inBufferUsageFlags;
889 VkMemoryRequirements inBufferMemoryReqs;
893 inBufferUsageFlags = readFromStorage ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
897 inBufferUsageFlags = readFromStorage ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
900 const VkBufferCreateInfo inBufferParams =
902 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
903 DE_NULL, // const void* pNext;
904 0u, // VkBufferCreateFlags flags;
905 m_inBufferAccessRange, // VkDeviceSize size;
906 inBufferUsageFlags, // VkBufferUsageFlags usage;
907 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
908 VK_QUEUE_FAMILY_IGNORED, // deUint32 queueFamilyIndexCount;
909 DE_NULL // const deUint32* pQueueFamilyIndices;
912 m_inBuffer = createBuffer(vk, *m_device, &inBufferParams);
914 inBufferMemoryReqs = getBufferMemoryRequirements(vk, *m_device, *m_inBuffer);
915 m_inBufferAllocSize = inBufferMemoryReqs.size;
916 m_inBufferAlloc = memAlloc.allocate(inBufferMemoryReqs, MemoryRequirement::HostVisible);
918 // Size of the most restrictive bound
919 m_inBufferMaxAccessRange = min(m_inBufferAllocSize, min(inBufferParams.size, m_inBufferAccessRange));
921 VK_CHECK(vk.bindBufferMemory(*m_device, *m_inBuffer, m_inBufferAlloc->getMemory(), m_inBufferAlloc->getOffset()));
922 populateBufferWithTestValues(m_inBufferAlloc->getHostPtr(), m_inBufferAllocSize, m_bufferFormat);
923 flushMappedMemoryRange(vk, *m_device, m_inBufferAlloc->getMemory(), m_inBufferAlloc->getOffset(), VK_WHOLE_SIZE);
925 log << tcu::TestLog::Message << "inBufferAllocSize = " << m_inBufferAllocSize << tcu::TestLog::EndMessage;
926 log << tcu::TestLog::Message << "inBufferMaxAccessRange = " << m_inBufferMaxAccessRange << tcu::TestLog::EndMessage;
929 // Create buffer to write data into
931 VkMemoryRequirements outBufferMemoryReqs;
932 const VkBufferUsageFlags outBufferUsageFlags = (m_shaderType == SHADER_TYPE_TEXEL_COPY) ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
933 : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
935 const VkBufferCreateInfo outBufferParams =
937 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
938 DE_NULL, // const void* pNext;
939 0u, // VkBufferCreateFlags flags;
940 m_outBufferAccessRange, // VkDeviceSize size;
941 outBufferUsageFlags, // VkBufferUsageFlags usage;
942 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
943 VK_QUEUE_FAMILY_IGNORED, // deUint32 queueFamilyIndexCount;
944 DE_NULL // const deUint32* pQueueFamilyIndices;
947 m_outBuffer = createBuffer(vk, *m_device, &outBufferParams);
949 outBufferMemoryReqs = getBufferMemoryRequirements(vk, *m_device, *m_outBuffer);
950 m_outBufferAllocSize = outBufferMemoryReqs.size;
951 m_outBufferAlloc = memAlloc.allocate(outBufferMemoryReqs, MemoryRequirement::HostVisible);
953 #ifdef CTS_USES_VULKANSC
954 if (m_context.getTestContext().getCommandLine().isSubProcess())
955 #endif // CTS_USES_VULKANSC
957 // If we are requesting access out of the memory that backs the buffer, make sure the test is able to do so.
958 if (m_accessOutOfBackingMemory)
960 if (m_outBufferAllocSize >= ((RobustBufferAccessTest::s_testArraySize + 1) * RobustBufferAccessTest::s_numberOfBytesAccessed))
962 TCU_THROW(NotSupportedError, "Cannot access beyond the end of the memory that backs the buffer");
967 // Size of the most restrictive bound
968 m_outBufferMaxAccessRange = min(m_outBufferAllocSize, min(outBufferParams.size, m_outBufferAccessRange));
970 VK_CHECK(vk.bindBufferMemory(*m_device, *m_outBuffer, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset()));
971 deMemset(m_outBufferAlloc->getHostPtr(), 0xFF, (size_t)m_outBufferAllocSize);
972 flushMappedMemoryRange(vk, *m_device, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset(), VK_WHOLE_SIZE);
974 log << tcu::TestLog::Message << "outBufferAllocSize = " << m_outBufferAllocSize << tcu::TestLog::EndMessage;
975 log << tcu::TestLog::Message << "outBufferMaxAccessRange = " << m_outBufferMaxAccessRange << tcu::TestLog::EndMessage;
978 // Create buffer for indices/offsets
986 IndicesBuffer indices = { 0, 0 };
988 const VkBufferCreateInfo indicesBufferParams =
990 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
991 DE_NULL, // const void* pNext;
992 0u, // VkBufferCreateFlags flags;
993 sizeof(IndicesBuffer), // VkDeviceSize size;
994 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, // VkBufferUsageFlags usage;
995 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
996 VK_QUEUE_FAMILY_IGNORED, // deUint32 queueFamilyIndexCount;
997 DE_NULL, // const deUint32* pQueueFamilyIndices;
1000 m_indicesBuffer = createBuffer(vk, *m_device, &indicesBufferParams);
1001 m_indicesBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_indicesBuffer), MemoryRequirement::HostVisible);
1003 VK_CHECK(vk.bindBufferMemory(*m_device, *m_indicesBuffer, m_indicesBufferAlloc->getMemory(), m_indicesBufferAlloc->getOffset()));
1005 if (m_accessOutOfBackingMemory)
1007 if (m_bufferAccessType == BUFFER_ACCESS_TYPE_WRITE)
1009 indices.outIndex = RobustBufferAccessTest::s_testArraySize - 1;
1013 indices.inIndex = RobustBufferAccessTest::s_testArraySize - 1;
1017 deMemcpy(m_indicesBufferAlloc->getHostPtr(), &indices, sizeof(IndicesBuffer));
1019 flushMappedMemoryRange(vk, *m_device, m_indicesBufferAlloc->getMemory(), m_indicesBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1021 log << tcu::TestLog::Message << "inIndex = " << indices.inIndex << tcu::TestLog::EndMessage;
1022 log << tcu::TestLog::Message << "outIndex = " << indices.outIndex << tcu::TestLog::EndMessage;
1025 // Create descriptor data
1027 VkDescriptorType inBufferDescriptorType;
1028 VkDescriptorType outBufferDescriptorType;
1032 inBufferDescriptorType = readFromStorage ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
1033 outBufferDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
1037 inBufferDescriptorType = readFromStorage ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1038 outBufferDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1041 DescriptorPoolBuilder descriptorPoolBuilder;
1042 descriptorPoolBuilder.addType(inBufferDescriptorType, 1u);
1043 descriptorPoolBuilder.addType(outBufferDescriptorType, 1u);
1044 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u);
1045 m_descriptorPool = descriptorPoolBuilder.build(vk, *m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1047 DescriptorSetLayoutBuilder setLayoutBuilder;
1048 setLayoutBuilder.addSingleBinding(inBufferDescriptorType, VK_SHADER_STAGE_ALL);
1049 setLayoutBuilder.addSingleBinding(outBufferDescriptorType, VK_SHADER_STAGE_ALL);
1050 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
1051 m_descriptorSetLayout = setLayoutBuilder.build(vk, *m_device);
1053 const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo =
1055 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
1056 DE_NULL, // const void* pNext;
1057 *m_descriptorPool, // VkDescriptorPool descriptorPool;
1058 1u, // deUint32 setLayoutCount;
1059 &m_descriptorSetLayout.get() // const VkDescriptorSetLayout* pSetLayouts;
1062 m_descriptorSet = allocateDescriptorSet(vk, *m_device, &descriptorSetAllocateInfo);
1064 DescriptorSetUpdateBuilder setUpdateBuilder;
1068 const VkBufferViewCreateInfo inBufferViewCreateInfo =
1070 VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType;
1071 DE_NULL, // const void* pNext;
1072 0u, // VkBufferViewCreateFlags flags;
1073 *m_inBuffer, // VkBuffer buffer;
1074 m_bufferFormat, // VkFormat format;
1075 0ull, // VkDeviceSize offset;
1076 m_inBufferAccessRange // VkDeviceSize range;
1078 m_inTexelBufferView = createBufferView(vk, *m_device, &inBufferViewCreateInfo, DE_NULL);
1080 const VkBufferViewCreateInfo outBufferViewCreateInfo =
1082 VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType;
1083 DE_NULL, // const void* pNext;
1084 0u, // VkBufferViewCreateFlags flags;
1085 *m_outBuffer, // VkBuffer buffer;
1086 m_bufferFormat, // VkFormat format;
1087 0ull, // VkDeviceSize offset;
1088 m_outBufferAccessRange, // VkDeviceSize range;
1090 m_outTexelBufferView = createBufferView(vk, *m_device, &outBufferViewCreateInfo, DE_NULL);
1092 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), inBufferDescriptorType, &m_inTexelBufferView.get());
1093 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), outBufferDescriptorType, &m_outTexelBufferView.get());
1097 const VkDescriptorBufferInfo inBufferDescriptorInfo = makeDescriptorBufferInfo(*m_inBuffer, 0ull, m_inBufferAccessRange);
1098 const VkDescriptorBufferInfo outBufferDescriptorInfo = makeDescriptorBufferInfo(*m_outBuffer, 0ull, m_outBufferAccessRange);
1100 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), inBufferDescriptorType, &inBufferDescriptorInfo);
1101 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), outBufferDescriptorType, &outBufferDescriptorInfo);
1104 const VkDescriptorBufferInfo indicesBufferDescriptorInfo = makeDescriptorBufferInfo(*m_indicesBuffer, 0ull, 8ull);
1105 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &indicesBufferDescriptorInfo);
1107 setUpdateBuilder.update(vk, *m_device);
1112 const VkFenceCreateInfo fenceParams =
1114 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
1115 DE_NULL, // const void* pNext;
1116 0u // VkFenceCreateFlags flags;
1119 m_fence = createFence(vk, *m_device, &fenceParams);
1123 vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &m_queue);
1125 if (m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
1127 m_testEnvironment = de::MovePtr<TestEnvironment>(new ComputeEnvironment(m_context, *m_deviceDriver, *m_device, *m_descriptorSetLayout, *m_descriptorSet, m_testPipelineRobustness));
1133 const VkVertexInputBindingDescription vertexInputBindingDescription =
1135 0u, // deUint32 binding;
1136 sizeof(tcu::Vec4), // deUint32 strideInBytes;
1137 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
1140 const VkVertexInputAttributeDescription vertexInputAttributeDescription =
1142 0u, // deUint32 location;
1143 0u, // deUint32 binding;
1144 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
1145 0u // deUint32 offset;
1148 const Vec4 vertices[] =
1150 Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1151 Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1152 Vec4(1.0f, -1.0f, 0.0f, 1.0f),
1155 // Create vertex buffer
1157 const VkDeviceSize vertexBufferSize = (VkDeviceSize)(4u * sizeof(tcu::Vec4));
1158 const VkBufferCreateInfo vertexBufferParams =
1160 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1161 DE_NULL, // const void* pNext;
1162 0u, // VkBufferCreateFlags flags;
1163 vertexBufferSize, // VkDeviceSize size;
1164 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
1165 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1166 VK_QUEUE_FAMILY_IGNORED, // deUint32 queueFamilyIndexCount;
1167 DE_NULL // const deUint32* pQueueFamilyIndices;
1170 DE_ASSERT(vertexBufferSize > 0);
1172 m_vertexBuffer = createBuffer(vk, *m_device, &vertexBufferParams);
1173 m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_vertexBuffer), MemoryRequirement::HostVisible);
1175 VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
1177 // Load vertices into vertex buffer
1178 deMemcpy(m_vertexBufferAlloc->getHostPtr(), vertices, sizeof(tcu::Vec4) * DE_LENGTH_OF_ARRAY(vertices));
1179 flushMappedMemoryRange(vk, *m_device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1182 const GraphicsEnvironment::DrawConfig drawWithOneVertexBuffer =
1184 std::vector<VkBuffer>(1, *m_vertexBuffer), // std::vector<VkBuffer> vertexBuffers;
1185 DE_LENGTH_OF_ARRAY(vertices), // deUint32 vertexCount;
1186 1, // deUint32 instanceCount;
1187 DE_NULL, // VkBuffer indexBuffer;
1188 0u, // deUint32 indexCount;
1191 m_testEnvironment = de::MovePtr<TestEnvironment>(new GraphicsEnvironment(m_context,
1194 *m_descriptorSetLayout,
1196 GraphicsEnvironment::VertexBindings(1, vertexInputBindingDescription),
1197 GraphicsEnvironment::VertexAttributes(1, vertexInputAttributeDescription),
1198 drawWithOneVertexBuffer,
1199 m_testPipelineRobustness));
1203 BufferAccessInstance::~BufferAccessInstance(void)
1207 // Verifies if the buffer has the value initialized by BufferAccessInstance::populateReadBuffer at a given offset.
1208 bool BufferAccessInstance::isExpectedValueFromInBuffer (VkDeviceSize offsetInBytes, const void* valuePtr, VkDeviceSize valueSize)
1210 DE_ASSERT(offsetInBytes % 4 == 0);
1211 DE_ASSERT(offsetInBytes < m_inBufferAllocSize);
1213 const deUint32 valueIndex = deUint32(offsetInBytes / 4) + 2;
1215 if (isUintFormat(m_bufferFormat))
1217 return !deMemCmp(valuePtr, &valueIndex, (size_t)valueSize);
1219 else if (isIntFormat(m_bufferFormat))
1221 const deInt32 value = -deInt32(valueIndex);
1222 return !deMemCmp(valuePtr, &value, (size_t)valueSize);
1224 else if (isFloatFormat(m_bufferFormat))
1226 const float value = float(valueIndex);
1227 return !deMemCmp(valuePtr, &value, (size_t)valueSize);
1229 else if (m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1231 const deUint32 r = ((valueIndex + 0) & ((2u << 10) - 1u));
1232 const deUint32 g = ((valueIndex + 1) & ((2u << 10) - 1u));
1233 const deUint32 b = ((valueIndex + 2) & ((2u << 10) - 1u));
1234 const deUint32 a = ((valueIndex + 0) & ((2u << 2) - 1u));
1235 const deUint32 abgr = (a << 30) | (b << 20) | (g << 10) | r;
1237 return !deMemCmp(valuePtr, &abgr, (size_t)valueSize);
1246 bool BufferAccessInstance::isOutBufferValueUnchanged (VkDeviceSize offsetInBytes, VkDeviceSize valueSize)
1248 const deUint8 *const outValuePtr = (deUint8*)m_outBufferAlloc->getHostPtr() + offsetInBytes;
1249 const deUint32 defaultValue = 0xFFFFFFFFu;
1251 return !deMemCmp(outValuePtr, &defaultValue, (size_t)valueSize);
1254 tcu::TestStatus BufferAccessInstance::iterate (void)
1256 const DeviceInterface& vk = *m_deviceDriver;
1257 const vk::VkCommandBuffer cmdBuffer = m_testEnvironment->getCommandBuffer();
1259 // Submit command buffer
1261 const VkSubmitInfo submitInfo =
1263 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
1264 DE_NULL, // const void* pNext;
1265 0u, // deUint32 waitSemaphoreCount;
1266 DE_NULL, // const VkSemaphore* pWaitSemaphores;
1267 DE_NULL, // const VkPIpelineStageFlags* pWaitDstStageMask;
1268 1u, // deUint32 commandBufferCount;
1269 &cmdBuffer, // const VkCommandBuffer* pCommandBuffers;
1270 0u, // deUint32 signalSemaphoreCount;
1271 DE_NULL // const VkSemaphore* pSignalSemaphores;
1274 VK_CHECK(vk.resetFences(*m_device, 1, &m_fence.get()));
1275 VK_CHECK(vk.queueSubmit(m_queue, 1, &submitInfo, *m_fence));
1276 VK_CHECK(vk.waitForFences(*m_device, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
1279 // Prepare result buffer for read
1281 const VkMappedMemoryRange outBufferRange =
1283 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType;
1284 DE_NULL, // const void* pNext;
1285 m_outBufferAlloc->getMemory(), // VkDeviceMemory mem;
1286 0ull, // VkDeviceSize offset;
1287 m_outBufferAllocSize, // VkDeviceSize size;
1290 VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
1294 return tcu::TestStatus::pass("All values OK");
1296 return tcu::TestStatus::fail("Invalid value(s) found");
1299 bool BufferAccessInstance::verifyResult (void)
1301 std::ostringstream logMsg;
1302 tcu::TestLog& log = m_context.getTestContext().getLog();
1303 const bool isReadAccess = !!(m_bufferAccessType == BUFFER_ACCESS_TYPE_READ || m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE);
1304 const void* inDataPtr = m_inBufferAlloc->getHostPtr();
1305 const void* outDataPtr = m_outBufferAlloc->getHostPtr();
1307 deUint32 valueNdx = 0;
1308 const VkDeviceSize maxAccessRange = isReadAccess ? m_inBufferMaxAccessRange : m_outBufferMaxAccessRange;
1310 for (VkDeviceSize offsetInBytes = 0; offsetInBytes < m_outBufferAllocSize; offsetInBytes += 4)
1312 deUint8* outValuePtr = (deUint8*)outDataPtr + offsetInBytes;
1313 const size_t outValueSize = (size_t)min(4, (m_outBufferAllocSize - offsetInBytes));
1315 if (offsetInBytes >= RobustBufferAccessTest::s_numberOfBytesAccessed)
1317 // The shader will only write 16 values into the result buffer. The rest of the values
1318 // should remain unchanged or may be modified if we are writing out of bounds.
1319 if (!isOutBufferValueUnchanged(offsetInBytes, outValueSize)
1320 && (isReadAccess || !isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, 4)))
1322 logMsg << "\nValue " << valueNdx++ << " has been modified with an unknown value: " << *((deUint32 *)outValuePtr);
1328 const deInt32 distanceToOutOfBounds = (deInt32)maxAccessRange - (deInt32)offsetInBytes;
1329 bool isOutOfBoundsAccess = false;
1331 logMsg << "\n" << valueNdx++ << ": ";
1333 logValue(logMsg, outValuePtr, m_bufferFormat, outValueSize);
1335 if (m_accessOutOfBackingMemory)
1337 isOutOfBoundsAccess = true;
1341 // Check if the shader operation accessed an operand located less than 16 bytes away
1342 // from the out of bounds address.
1344 deUint32 operandSize = 0;
1346 switch (m_shaderType)
1348 case SHADER_TYPE_SCALAR_COPY:
1349 operandSize = 4; // Size of scalar
1352 case SHADER_TYPE_VECTOR_COPY:
1353 operandSize = 4 * ((m_bufferFormat == vk::VK_FORMAT_R64_UINT || m_bufferFormat == vk::VK_FORMAT_R64_SINT) ? 8 : 4);// Size of vec4
1356 case SHADER_TYPE_MATRIX_COPY:
1357 operandSize = 4 * 16; // Size of mat4
1360 case SHADER_TYPE_TEXEL_COPY:
1361 operandSize = mapVkFormat(m_bufferFormat).getPixelSize();
1368 isOutOfBoundsAccess = (maxAccessRange < 16)
1369 || (((offsetInBytes / operandSize + 1) * operandSize) > (maxAccessRange - 16));
1372 if (isOutOfBoundsAccess)
1374 logMsg << " (out of bounds " << (isReadAccess ? "read": "write") << ")";
1376 const bool isValuePartiallyOutOfBounds = ((distanceToOutOfBounds > 0) && ((deUint32)distanceToOutOfBounds < 4));
1377 bool isValidValue = false;
1379 if (isValuePartiallyOutOfBounds && !m_accessOutOfBackingMemory)
1381 // The value is partially out of bounds
1383 bool isOutOfBoundsPartOk = true;
1384 bool isWithinBoundsPartOk = true;
1388 isWithinBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, distanceToOutOfBounds);
1389 isOutOfBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, (deUint8*)outValuePtr + distanceToOutOfBounds , outValueSize - distanceToOutOfBounds);
1393 isWithinBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, distanceToOutOfBounds)
1394 || isOutBufferValueUnchanged(offsetInBytes, distanceToOutOfBounds);
1396 isOutOfBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, (deUint8*)outValuePtr + distanceToOutOfBounds, outValueSize - distanceToOutOfBounds)
1397 || isOutBufferValueUnchanged(offsetInBytes + distanceToOutOfBounds, outValueSize - distanceToOutOfBounds);
1400 logMsg << ", first " << distanceToOutOfBounds << " byte(s) " << (isWithinBoundsPartOk ? "OK": "wrong");
1401 logMsg << ", last " << outValueSize - distanceToOutOfBounds << " byte(s) " << (isOutOfBoundsPartOk ? "OK": "wrong");
1403 isValidValue = isWithinBoundsPartOk && isOutOfBoundsPartOk;
1409 isValidValue = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, outValueSize);
1413 isValidValue = isOutBufferValueUnchanged(offsetInBytes, outValueSize);
1417 // Out of bounds writes may modify values withing the memory ranges bound to the buffer
1418 isValidValue = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, outValueSize);
1421 logMsg << ", OK, written within the memory range bound to the buffer";
1428 // Check if we are satisfying the [0, 0, 0, x] pattern, where x may be either 0 or 1,
1429 // or the maximum representable positive integer value (if the format is integer-based).
1431 const bool canMatchVec4Pattern = (isReadAccess
1432 && !isValuePartiallyOutOfBounds
1433 && (m_shaderType == SHADER_TYPE_VECTOR_COPY || m_shaderType == SHADER_TYPE_TEXEL_COPY)
1434 && ((offsetInBytes / 4 + 1) % 4 == 0 || m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32));
1435 bool matchesVec4Pattern = false;
1437 if (canMatchVec4Pattern)
1439 if (m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1440 matchesVec4Pattern = verifyOutOfBoundsVec4(outValuePtr, m_bufferFormat);
1442 matchesVec4Pattern = verifyOutOfBoundsVec4(reinterpret_cast<deUint32*>(outValuePtr) - 3, m_bufferFormat);
1445 if (!canMatchVec4Pattern || !matchesVec4Pattern)
1447 logMsg << ". Failed: ";
1451 logMsg << "expected value within the buffer range or 0";
1453 if (canMatchVec4Pattern)
1454 logMsg << ", or the [0, 0, 0, x] pattern";
1458 logMsg << "written out of the range";
1465 else // We are within bounds
1469 if (!isExpectedValueFromInBuffer(offsetInBytes, outValuePtr, 4))
1471 logMsg << ", Failed: unexpected value";
1477 // Out of bounds writes may change values within the bounds.
1478 if (!isValueWithinBufferOrZero(inDataPtr, m_inBufferAccessRange, outValuePtr, 4))
1480 logMsg << ", Failed: unexpected value";
1488 log << tcu::TestLog::Message << logMsg.str() << tcu::TestLog::EndMessage;
1493 // BufferReadInstance
1495 BufferReadInstance::BufferReadInstance (Context& context,
1496 Move<VkDevice> device,
1497 #ifndef CTS_USES_VULKANSC
1498 de::MovePtr<vk::DeviceDriver> deviceDriver,
1500 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
1501 #endif // CTS_USES_VULKANSC
1502 ShaderType shaderType,
1503 VkShaderStageFlags shaderStage,
1504 VkFormat bufferFormat,
1505 bool readFromStorage,
1506 VkDeviceSize inBufferAccessRange,
1507 bool accessOutOfBackingMemory,
1508 bool testPipelineRobustness)
1510 : BufferAccessInstance (context, device, deviceDriver, shaderType, shaderStage, bufferFormat,
1511 readFromStorage ? BUFFER_ACCESS_TYPE_READ_FROM_STORAGE : BUFFER_ACCESS_TYPE_READ,
1512 inBufferAccessRange,
1513 RobustBufferAccessTest::s_numberOfBytesAccessed, // outBufferAccessRange
1514 accessOutOfBackingMemory,
1515 testPipelineRobustness)
1519 // BufferWriteInstance
1521 BufferWriteInstance::BufferWriteInstance (Context& context,
1522 Move<VkDevice> device,
1523 #ifndef CTS_USES_VULKANSC
1524 de::MovePtr<vk::DeviceDriver> deviceDriver,
1526 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
1527 #endif // CTS_USES_VULKANSC
1528 ShaderType shaderType,
1529 VkShaderStageFlags shaderStage,
1530 VkFormat bufferFormat,
1531 VkDeviceSize writeBufferAccessRange,
1532 bool accessOutOfBackingMemory,
1533 bool testPipelineRobustness)
1535 : BufferAccessInstance (context, device, deviceDriver, shaderType, shaderStage, bufferFormat,
1536 BUFFER_ACCESS_TYPE_WRITE,
1537 RobustBufferAccessTest::s_numberOfBytesAccessed, // inBufferAccessRange
1538 writeBufferAccessRange,
1539 accessOutOfBackingMemory,
1540 testPipelineRobustness)
1544 // Test node creation functions
1546 static const char* getShaderStageName (VkShaderStageFlagBits shaderStage)
1548 switch (shaderStage)
1550 case VK_SHADER_STAGE_VERTEX_BIT: return "vertex";
1551 case VK_SHADER_STAGE_FRAGMENT_BIT: return "fragment";
1552 case VK_SHADER_STAGE_COMPUTE_BIT: return "compute";
1553 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return "tess_control";
1554 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return "tess_eval";
1555 case VK_SHADER_STAGE_GEOMETRY_BIT: return "geometry";
1564 static void addBufferAccessTests (tcu::TestContext& testCtx, tcu::TestCaseGroup* parentNode, bool testPipelineRobustness)
1566 struct BufferRangeConfig
1572 const VkShaderStageFlagBits bufferAccessStages[] =
1574 VK_SHADER_STAGE_VERTEX_BIT,
1575 VK_SHADER_STAGE_FRAGMENT_BIT,
1576 VK_SHADER_STAGE_COMPUTE_BIT,
1579 const VkFormat bufferFormats[] =
1585 VK_FORMAT_R32_SFLOAT
1588 const VkFormat texelBufferFormats[] =
1590 VK_FORMAT_R32G32B32A32_SINT,
1591 VK_FORMAT_R32G32B32A32_UINT,
1592 VK_FORMAT_R32G32B32A32_SFLOAT,
1594 VK_FORMAT_A2B10G10R10_UNORM_PACK32
1597 const BufferRangeConfig bufferRangeConfigs[] =
1599 { "range_1_byte", 1ull },
1600 { "range_3_bytes", 3ull },
1601 { "range_4_bytes", 4ull }, // size of float
1602 { "range_32_bytes", 32ull }, // size of half mat4
1605 const BufferRangeConfig texelBufferRangeConfigs[] =
1607 { "range_1_texel", 1u },
1608 { "range_3_texels", 3u },
1611 const char* shaderTypeNames[SHADER_TYPE_COUNT] =
1619 for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(bufferAccessStages); stageNdx++)
1621 const VkShaderStageFlagBits stage = bufferAccessStages[stageNdx];
1622 de::MovePtr<tcu::TestCaseGroup> stageTests (new tcu::TestCaseGroup(testCtx, getShaderStageName(stage), ""));
1624 for (int shaderTypeNdx = 0; shaderTypeNdx < SHADER_TYPE_COUNT; shaderTypeNdx++)
1626 const VkFormat* formats;
1627 size_t formatsLength;
1628 const BufferRangeConfig* ranges;
1629 size_t rangesLength;
1630 deUint32 rangeMultiplier;
1631 de::MovePtr<tcu::TestCaseGroup> shaderTypeTests (new tcu::TestCaseGroup(testCtx, shaderTypeNames[shaderTypeNdx], ""));
1633 if ((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY)
1635 formats = texelBufferFormats;
1636 formatsLength = DE_LENGTH_OF_ARRAY(texelBufferFormats);
1638 ranges = texelBufferRangeConfigs;
1639 rangesLength = DE_LENGTH_OF_ARRAY(texelBufferRangeConfigs);
1643 formats = bufferFormats;
1644 formatsLength = DE_LENGTH_OF_ARRAY(bufferFormats);
1646 ranges = bufferRangeConfigs;
1647 rangesLength = DE_LENGTH_OF_ARRAY(bufferRangeConfigs);
1650 for (size_t formatNdx = 0; formatNdx < formatsLength; formatNdx++)
1652 const VkFormat bufferFormat = formats[formatNdx];
1654 rangeMultiplier = ((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY) ? mapVkFormat(bufferFormat).getPixelSize() : 1;
1656 if (!isFloatFormat(bufferFormat) && ((ShaderType)shaderTypeNdx) == SHADER_TYPE_MATRIX_COPY)
1658 // Use SHADER_TYPE_MATRIX_COPY with floating-point formats only
1662 // Avoid too much duplication by excluding certain test cases
1663 if (testPipelineRobustness &&
1664 !(bufferFormat == VK_FORMAT_R32_UINT || bufferFormat == VK_FORMAT_R64_SINT || bufferFormat == VK_FORMAT_R32_SFLOAT || bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32))
1669 const std::string formatName = getFormatName(bufferFormat);
1670 de::MovePtr<tcu::TestCaseGroup> formatTests (new tcu::TestCaseGroup(testCtx, de::toLower(formatName.substr(10)).c_str(), ""));
1672 de::MovePtr<tcu::TestCaseGroup> uboReadTests (new tcu::TestCaseGroup(testCtx, "oob_uniform_read", ""));
1673 de::MovePtr<tcu::TestCaseGroup> ssboReadTests (new tcu::TestCaseGroup(testCtx, "oob_storage_read", ""));
1674 de::MovePtr<tcu::TestCaseGroup> ssboWriteTests (new tcu::TestCaseGroup(testCtx, "oob_storage_write", ""));
1676 for (size_t rangeNdx = 0; rangeNdx < rangesLength; rangeNdx++)
1678 const BufferRangeConfig& rangeConfig = ranges[rangeNdx];
1679 const VkDeviceSize rangeInBytes = rangeConfig.range * rangeMultiplier;
1681 uboReadTests->addChild(new RobustBufferReadTest(testCtx, rangeConfig.name, "", stage, (ShaderType)shaderTypeNdx, bufferFormat, testPipelineRobustness, rangeInBytes, false, false));
1683 // Avoid too much duplication by excluding certain test cases
1684 if (!testPipelineRobustness)
1685 ssboReadTests->addChild(new RobustBufferReadTest(testCtx, rangeConfig.name, "", stage, (ShaderType)shaderTypeNdx, bufferFormat, testPipelineRobustness, rangeInBytes, true, false));
1687 ssboWriteTests->addChild(new RobustBufferWriteTest(testCtx, rangeConfig.name, "", stage, (ShaderType)shaderTypeNdx, bufferFormat, testPipelineRobustness, rangeInBytes, false));
1691 formatTests->addChild(uboReadTests.release());
1692 formatTests->addChild(ssboReadTests.release());
1693 formatTests->addChild(ssboWriteTests.release());
1695 shaderTypeTests->addChild(formatTests.release());
1698 // Read/write out of the memory that backs the buffer
1700 de::MovePtr<tcu::TestCaseGroup> outOfAllocTests (new tcu::TestCaseGroup(testCtx, "out_of_alloc", ""));
1702 const VkFormat format = (((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY ) ? VK_FORMAT_R32G32B32A32_SFLOAT : VK_FORMAT_R32_SFLOAT);
1704 outOfAllocTests->addChild(new RobustBufferReadTest(testCtx, "oob_uniform_read", "", stage, (ShaderType)shaderTypeNdx, format, testPipelineRobustness, 16, false, true));
1706 // Avoid too much duplication by excluding certain test cases
1707 if (!testPipelineRobustness)
1708 outOfAllocTests->addChild(new RobustBufferReadTest(testCtx, "oob_storage_read", "", stage, (ShaderType)shaderTypeNdx, format, testPipelineRobustness, 16, true, true));
1710 outOfAllocTests->addChild(new RobustBufferWriteTest(testCtx, "oob_storage_write", "", stage, (ShaderType)shaderTypeNdx, format, testPipelineRobustness, 16, true));
1712 shaderTypeTests->addChild(outOfAllocTests.release());
1715 stageTests->addChild(shaderTypeTests.release());
1717 parentNode->addChild(stageTests.release());
1721 tcu::TestCaseGroup* createBufferAccessTests (tcu::TestContext& testCtx)
1723 de::MovePtr<tcu::TestCaseGroup> bufferAccessTests (new tcu::TestCaseGroup(testCtx, "buffer_access", ""));
1725 addBufferAccessTests(testCtx, bufferAccessTests.get(), false);
1727 return bufferAccessTests.release();
1730 #ifndef CTS_USES_VULKANSC
1731 tcu::TestCaseGroup* createPipelineRobustnessBufferAccessTests (tcu::TestContext& testCtx)
1733 de::MovePtr<tcu::TestCaseGroup> bufferAccessTests (new tcu::TestCaseGroup(testCtx, "pipeline_robustness_buffer_access", ""));
1734 addBufferAccessTests(testCtx, bufferAccessTests.get(), true);
1736 return bufferAccessTests.release();