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();
766 features2.features.shaderInt64 = VK_TRUE;
769 features2.features.vertexPipelineStoresAndAtomics = VK_TRUE;
772 features2.features.fragmentStoresAndAtomics = VK_TRUE;
774 #ifndef CTS_USES_VULKANSC
775 VkPhysicalDevicePipelineRobustnessFeaturesEXT pipelineRobustnessFeatures = initVulkanStructure();
776 if (m_testPipelineRobustness)
778 context.requireDeviceFunctionality("VK_EXT_pipeline_robustness");
780 const auto& vki = context.getInstanceInterface();
781 const auto physicalDevice = context.getPhysicalDevice();
783 pipelineRobustnessFeatures.pNext = features2.pNext;
784 features2.pNext = &pipelineRobustnessFeatures;
786 vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
790 const bool useFeatures2 = (m_testPipelineRobustness || is64BitsTest_ || isVertexTest_ || isFragmentTest_);
792 Move<VkDevice> device = createRobustBufferAccessDevice(context, (useFeatures2 ? &features2 : nullptr));
793 #ifndef CTS_USES_VULKANSC
794 de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device));
796 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));
797 #endif // CTS_USES_VULKANSC
799 return new BufferWriteInstance(context, device, deviceDriver, m_shaderType, m_shaderStage, m_bufferFormat, m_writeAccessRange, m_accessOutOfBackingMemory, m_testPipelineRobustness);
802 // BufferAccessInstance
804 BufferAccessInstance::BufferAccessInstance (Context& context,
805 Move<VkDevice> device,
806 #ifndef CTS_USES_VULKANSC
807 de::MovePtr<vk::DeviceDriver> deviceDriver,
809 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
810 #endif // CTS_USES_VULKANSC
811 ShaderType shaderType,
812 VkShaderStageFlags shaderStage,
813 VkFormat bufferFormat,
814 BufferAccessType bufferAccessType,
815 VkDeviceSize inBufferAccessRange,
816 VkDeviceSize outBufferAccessRange,
817 bool accessOutOfBackingMemory,
818 bool testPipelineRobustness)
819 : vkt::TestInstance (context)
821 , m_deviceDriver (deviceDriver)
822 , m_shaderType (shaderType)
823 , m_shaderStage (shaderStage)
824 , m_bufferFormat (bufferFormat)
825 , m_bufferAccessType (bufferAccessType)
826 , m_inBufferAccessRange (inBufferAccessRange)
827 , m_outBufferAccessRange (outBufferAccessRange)
828 , m_accessOutOfBackingMemory (accessOutOfBackingMemory)
829 , m_testPipelineRobustness (testPipelineRobustness)
831 const DeviceInterface& vk = *m_deviceDriver;
832 const auto& vki = context.getInstanceInterface();
833 const auto instance = context.getInstance();
834 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
835 const bool isTexelAccess = !!(m_shaderType == SHADER_TYPE_TEXEL_COPY);
836 const bool readFromStorage = !!(m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE);
837 const VkPhysicalDevice physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine());
838 SimpleAllocator memAlloc (vk, *m_device, getPhysicalDeviceMemoryProperties(vki, physicalDevice));
839 tcu::TestLog& log = m_context.getTestContext().getLog();
841 DE_ASSERT(RobustBufferAccessTest::s_numberOfBytesAccessed % sizeof(deUint32) == 0);
842 DE_ASSERT(inBufferAccessRange <= RobustBufferAccessTest::s_numberOfBytesAccessed);
843 DE_ASSERT(outBufferAccessRange <= RobustBufferAccessTest::s_numberOfBytesAccessed);
845 if (m_bufferFormat == VK_FORMAT_R64_UINT || m_bufferFormat == VK_FORMAT_R64_SINT)
847 context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
850 // Check storage support
851 if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
853 if (!context.getDeviceFeatures().vertexPipelineStoresAndAtomics)
855 TCU_THROW(NotSupportedError, "Stores not supported in vertex stage");
858 else if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
860 if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
862 TCU_THROW(NotSupportedError, "Stores not supported in fragment stage");
866 // Check format support
868 VkFormatFeatureFlags requiredFormatFeatures = 0;
869 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(vki, physicalDevice, m_bufferFormat);
873 requiredFormatFeatures = VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
876 if ((formatProperties.bufferFeatures & requiredFormatFeatures) != requiredFormatFeatures)
878 TCU_THROW(NotSupportedError, (std::string("Format cannot be used in uniform and storage") + (isTexelAccess ? " texel" : "") + " buffers: "
879 + getFormatName(m_bufferFormat)).c_str());
883 // Create buffer to read data from
885 VkBufferUsageFlags inBufferUsageFlags;
886 VkMemoryRequirements inBufferMemoryReqs;
890 inBufferUsageFlags = readFromStorage ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
894 inBufferUsageFlags = readFromStorage ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
897 const VkBufferCreateInfo inBufferParams =
899 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
900 DE_NULL, // const void* pNext;
901 0u, // VkBufferCreateFlags flags;
902 m_inBufferAccessRange, // VkDeviceSize size;
903 inBufferUsageFlags, // VkBufferUsageFlags usage;
904 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
905 VK_QUEUE_FAMILY_IGNORED, // deUint32 queueFamilyIndexCount;
906 DE_NULL // const deUint32* pQueueFamilyIndices;
909 m_inBuffer = createBuffer(vk, *m_device, &inBufferParams);
911 inBufferMemoryReqs = getBufferMemoryRequirements(vk, *m_device, *m_inBuffer);
912 m_inBufferAllocSize = inBufferMemoryReqs.size;
913 m_inBufferAlloc = memAlloc.allocate(inBufferMemoryReqs, MemoryRequirement::HostVisible);
915 // Size of the most restrictive bound
916 m_inBufferMaxAccessRange = min(m_inBufferAllocSize, min(inBufferParams.size, m_inBufferAccessRange));
918 VK_CHECK(vk.bindBufferMemory(*m_device, *m_inBuffer, m_inBufferAlloc->getMemory(), m_inBufferAlloc->getOffset()));
919 populateBufferWithTestValues(m_inBufferAlloc->getHostPtr(), m_inBufferAllocSize, m_bufferFormat);
920 flushMappedMemoryRange(vk, *m_device, m_inBufferAlloc->getMemory(), m_inBufferAlloc->getOffset(), VK_WHOLE_SIZE);
922 log << tcu::TestLog::Message << "inBufferAllocSize = " << m_inBufferAllocSize << tcu::TestLog::EndMessage;
923 log << tcu::TestLog::Message << "inBufferMaxAccessRange = " << m_inBufferMaxAccessRange << tcu::TestLog::EndMessage;
926 // Create buffer to write data into
928 VkMemoryRequirements outBufferMemoryReqs;
929 const VkBufferUsageFlags outBufferUsageFlags = (m_shaderType == SHADER_TYPE_TEXEL_COPY) ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
930 : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
932 const VkBufferCreateInfo outBufferParams =
934 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
935 DE_NULL, // const void* pNext;
936 0u, // VkBufferCreateFlags flags;
937 m_outBufferAccessRange, // VkDeviceSize size;
938 outBufferUsageFlags, // VkBufferUsageFlags usage;
939 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
940 VK_QUEUE_FAMILY_IGNORED, // deUint32 queueFamilyIndexCount;
941 DE_NULL // const deUint32* pQueueFamilyIndices;
944 m_outBuffer = createBuffer(vk, *m_device, &outBufferParams);
946 outBufferMemoryReqs = getBufferMemoryRequirements(vk, *m_device, *m_outBuffer);
947 m_outBufferAllocSize = outBufferMemoryReqs.size;
948 m_outBufferAlloc = memAlloc.allocate(outBufferMemoryReqs, MemoryRequirement::HostVisible);
950 #ifdef CTS_USES_VULKANSC
951 if (m_context.getTestContext().getCommandLine().isSubProcess())
952 #endif // CTS_USES_VULKANSC
954 // If we are requesting access out of the memory that backs the buffer, make sure the test is able to do so.
955 if (m_accessOutOfBackingMemory)
957 if (m_outBufferAllocSize >= ((RobustBufferAccessTest::s_testArraySize + 1) * RobustBufferAccessTest::s_numberOfBytesAccessed))
959 TCU_THROW(NotSupportedError, "Cannot access beyond the end of the memory that backs the buffer");
964 // Size of the most restrictive bound
965 m_outBufferMaxAccessRange = min(m_outBufferAllocSize, min(outBufferParams.size, m_outBufferAccessRange));
967 VK_CHECK(vk.bindBufferMemory(*m_device, *m_outBuffer, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset()));
968 deMemset(m_outBufferAlloc->getHostPtr(), 0xFF, (size_t)m_outBufferAllocSize);
969 flushMappedMemoryRange(vk, *m_device, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset(), VK_WHOLE_SIZE);
971 log << tcu::TestLog::Message << "outBufferAllocSize = " << m_outBufferAllocSize << tcu::TestLog::EndMessage;
972 log << tcu::TestLog::Message << "outBufferMaxAccessRange = " << m_outBufferMaxAccessRange << tcu::TestLog::EndMessage;
975 // Create buffer for indices/offsets
983 IndicesBuffer indices = { 0, 0 };
985 const VkBufferCreateInfo indicesBufferParams =
987 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
988 DE_NULL, // const void* pNext;
989 0u, // VkBufferCreateFlags flags;
990 sizeof(IndicesBuffer), // VkDeviceSize size;
991 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, // VkBufferUsageFlags usage;
992 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
993 VK_QUEUE_FAMILY_IGNORED, // deUint32 queueFamilyIndexCount;
994 DE_NULL, // const deUint32* pQueueFamilyIndices;
997 m_indicesBuffer = createBuffer(vk, *m_device, &indicesBufferParams);
998 m_indicesBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_indicesBuffer), MemoryRequirement::HostVisible);
1000 VK_CHECK(vk.bindBufferMemory(*m_device, *m_indicesBuffer, m_indicesBufferAlloc->getMemory(), m_indicesBufferAlloc->getOffset()));
1002 if (m_accessOutOfBackingMemory)
1004 if (m_bufferAccessType == BUFFER_ACCESS_TYPE_WRITE)
1006 indices.outIndex = RobustBufferAccessTest::s_testArraySize - 1;
1010 indices.inIndex = RobustBufferAccessTest::s_testArraySize - 1;
1014 deMemcpy(m_indicesBufferAlloc->getHostPtr(), &indices, sizeof(IndicesBuffer));
1016 flushMappedMemoryRange(vk, *m_device, m_indicesBufferAlloc->getMemory(), m_indicesBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1018 log << tcu::TestLog::Message << "inIndex = " << indices.inIndex << tcu::TestLog::EndMessage;
1019 log << tcu::TestLog::Message << "outIndex = " << indices.outIndex << tcu::TestLog::EndMessage;
1022 // Create descriptor data
1024 VkDescriptorType inBufferDescriptorType;
1025 VkDescriptorType outBufferDescriptorType;
1029 inBufferDescriptorType = readFromStorage ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
1030 outBufferDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
1034 inBufferDescriptorType = readFromStorage ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1035 outBufferDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1038 DescriptorPoolBuilder descriptorPoolBuilder;
1039 descriptorPoolBuilder.addType(inBufferDescriptorType, 1u);
1040 descriptorPoolBuilder.addType(outBufferDescriptorType, 1u);
1041 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u);
1042 m_descriptorPool = descriptorPoolBuilder.build(vk, *m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1044 DescriptorSetLayoutBuilder setLayoutBuilder;
1045 setLayoutBuilder.addSingleBinding(inBufferDescriptorType, VK_SHADER_STAGE_ALL);
1046 setLayoutBuilder.addSingleBinding(outBufferDescriptorType, VK_SHADER_STAGE_ALL);
1047 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
1048 m_descriptorSetLayout = setLayoutBuilder.build(vk, *m_device);
1050 const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo =
1052 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
1053 DE_NULL, // const void* pNext;
1054 *m_descriptorPool, // VkDescriptorPool descriptorPool;
1055 1u, // deUint32 setLayoutCount;
1056 &m_descriptorSetLayout.get() // const VkDescriptorSetLayout* pSetLayouts;
1059 m_descriptorSet = allocateDescriptorSet(vk, *m_device, &descriptorSetAllocateInfo);
1061 DescriptorSetUpdateBuilder setUpdateBuilder;
1065 const VkBufferViewCreateInfo inBufferViewCreateInfo =
1067 VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType;
1068 DE_NULL, // const void* pNext;
1069 0u, // VkBufferViewCreateFlags flags;
1070 *m_inBuffer, // VkBuffer buffer;
1071 m_bufferFormat, // VkFormat format;
1072 0ull, // VkDeviceSize offset;
1073 m_inBufferAccessRange // VkDeviceSize range;
1075 m_inTexelBufferView = createBufferView(vk, *m_device, &inBufferViewCreateInfo, DE_NULL);
1077 const VkBufferViewCreateInfo outBufferViewCreateInfo =
1079 VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType;
1080 DE_NULL, // const void* pNext;
1081 0u, // VkBufferViewCreateFlags flags;
1082 *m_outBuffer, // VkBuffer buffer;
1083 m_bufferFormat, // VkFormat format;
1084 0ull, // VkDeviceSize offset;
1085 m_outBufferAccessRange, // VkDeviceSize range;
1087 m_outTexelBufferView = createBufferView(vk, *m_device, &outBufferViewCreateInfo, DE_NULL);
1089 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), inBufferDescriptorType, &m_inTexelBufferView.get());
1090 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), outBufferDescriptorType, &m_outTexelBufferView.get());
1094 const VkDescriptorBufferInfo inBufferDescriptorInfo = makeDescriptorBufferInfo(*m_inBuffer, 0ull, m_inBufferAccessRange);
1095 const VkDescriptorBufferInfo outBufferDescriptorInfo = makeDescriptorBufferInfo(*m_outBuffer, 0ull, m_outBufferAccessRange);
1097 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), inBufferDescriptorType, &inBufferDescriptorInfo);
1098 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), outBufferDescriptorType, &outBufferDescriptorInfo);
1101 const VkDescriptorBufferInfo indicesBufferDescriptorInfo = makeDescriptorBufferInfo(*m_indicesBuffer, 0ull, 8ull);
1102 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &indicesBufferDescriptorInfo);
1104 setUpdateBuilder.update(vk, *m_device);
1109 const VkFenceCreateInfo fenceParams =
1111 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
1112 DE_NULL, // const void* pNext;
1113 0u // VkFenceCreateFlags flags;
1116 m_fence = createFence(vk, *m_device, &fenceParams);
1120 vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &m_queue);
1122 if (m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
1124 m_testEnvironment = de::MovePtr<TestEnvironment>(new ComputeEnvironment(m_context, *m_deviceDriver, *m_device, *m_descriptorSetLayout, *m_descriptorSet, m_testPipelineRobustness));
1130 const VkVertexInputBindingDescription vertexInputBindingDescription =
1132 0u, // deUint32 binding;
1133 sizeof(tcu::Vec4), // deUint32 strideInBytes;
1134 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
1137 const VkVertexInputAttributeDescription vertexInputAttributeDescription =
1139 0u, // deUint32 location;
1140 0u, // deUint32 binding;
1141 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
1142 0u // deUint32 offset;
1145 const Vec4 vertices[] =
1147 Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1148 Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1149 Vec4(1.0f, -1.0f, 0.0f, 1.0f),
1152 // Create vertex buffer
1154 const VkDeviceSize vertexBufferSize = (VkDeviceSize)(4u * sizeof(tcu::Vec4));
1155 const VkBufferCreateInfo vertexBufferParams =
1157 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1158 DE_NULL, // const void* pNext;
1159 0u, // VkBufferCreateFlags flags;
1160 vertexBufferSize, // VkDeviceSize size;
1161 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
1162 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1163 VK_QUEUE_FAMILY_IGNORED, // deUint32 queueFamilyIndexCount;
1164 DE_NULL // const deUint32* pQueueFamilyIndices;
1167 DE_ASSERT(vertexBufferSize > 0);
1169 m_vertexBuffer = createBuffer(vk, *m_device, &vertexBufferParams);
1170 m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_vertexBuffer), MemoryRequirement::HostVisible);
1172 VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
1174 // Load vertices into vertex buffer
1175 deMemcpy(m_vertexBufferAlloc->getHostPtr(), vertices, sizeof(tcu::Vec4) * DE_LENGTH_OF_ARRAY(vertices));
1176 flushMappedMemoryRange(vk, *m_device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1179 const GraphicsEnvironment::DrawConfig drawWithOneVertexBuffer =
1181 std::vector<VkBuffer>(1, *m_vertexBuffer), // std::vector<VkBuffer> vertexBuffers;
1182 DE_LENGTH_OF_ARRAY(vertices), // deUint32 vertexCount;
1183 1, // deUint32 instanceCount;
1184 DE_NULL, // VkBuffer indexBuffer;
1185 0u, // deUint32 indexCount;
1188 m_testEnvironment = de::MovePtr<TestEnvironment>(new GraphicsEnvironment(m_context,
1191 *m_descriptorSetLayout,
1193 GraphicsEnvironment::VertexBindings(1, vertexInputBindingDescription),
1194 GraphicsEnvironment::VertexAttributes(1, vertexInputAttributeDescription),
1195 drawWithOneVertexBuffer,
1196 m_testPipelineRobustness));
1200 BufferAccessInstance::~BufferAccessInstance(void)
1204 // Verifies if the buffer has the value initialized by BufferAccessInstance::populateReadBuffer at a given offset.
1205 bool BufferAccessInstance::isExpectedValueFromInBuffer (VkDeviceSize offsetInBytes, const void* valuePtr, VkDeviceSize valueSize)
1207 DE_ASSERT(offsetInBytes % 4 == 0);
1208 DE_ASSERT(offsetInBytes < m_inBufferAllocSize);
1210 const deUint32 valueIndex = deUint32(offsetInBytes / 4) + 2;
1212 if (isUintFormat(m_bufferFormat))
1214 return !deMemCmp(valuePtr, &valueIndex, (size_t)valueSize);
1216 else if (isIntFormat(m_bufferFormat))
1218 const deInt32 value = -deInt32(valueIndex);
1219 return !deMemCmp(valuePtr, &value, (size_t)valueSize);
1221 else if (isFloatFormat(m_bufferFormat))
1223 const float value = float(valueIndex);
1224 return !deMemCmp(valuePtr, &value, (size_t)valueSize);
1226 else if (m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1228 const deUint32 r = ((valueIndex + 0) & ((2u << 10) - 1u));
1229 const deUint32 g = ((valueIndex + 1) & ((2u << 10) - 1u));
1230 const deUint32 b = ((valueIndex + 2) & ((2u << 10) - 1u));
1231 const deUint32 a = ((valueIndex + 0) & ((2u << 2) - 1u));
1232 const deUint32 abgr = (a << 30) | (b << 20) | (g << 10) | r;
1234 return !deMemCmp(valuePtr, &abgr, (size_t)valueSize);
1243 bool BufferAccessInstance::isOutBufferValueUnchanged (VkDeviceSize offsetInBytes, VkDeviceSize valueSize)
1245 const deUint8 *const outValuePtr = (deUint8*)m_outBufferAlloc->getHostPtr() + offsetInBytes;
1246 const deUint32 defaultValue = 0xFFFFFFFFu;
1248 return !deMemCmp(outValuePtr, &defaultValue, (size_t)valueSize);
1251 tcu::TestStatus BufferAccessInstance::iterate (void)
1253 const DeviceInterface& vk = *m_deviceDriver;
1254 const vk::VkCommandBuffer cmdBuffer = m_testEnvironment->getCommandBuffer();
1256 // Submit command buffer
1258 const VkSubmitInfo submitInfo =
1260 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
1261 DE_NULL, // const void* pNext;
1262 0u, // deUint32 waitSemaphoreCount;
1263 DE_NULL, // const VkSemaphore* pWaitSemaphores;
1264 DE_NULL, // const VkPIpelineStageFlags* pWaitDstStageMask;
1265 1u, // deUint32 commandBufferCount;
1266 &cmdBuffer, // const VkCommandBuffer* pCommandBuffers;
1267 0u, // deUint32 signalSemaphoreCount;
1268 DE_NULL // const VkSemaphore* pSignalSemaphores;
1271 VK_CHECK(vk.resetFences(*m_device, 1, &m_fence.get()));
1272 VK_CHECK(vk.queueSubmit(m_queue, 1, &submitInfo, *m_fence));
1273 VK_CHECK(vk.waitForFences(*m_device, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
1276 // Prepare result buffer for read
1278 const VkMappedMemoryRange outBufferRange =
1280 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType;
1281 DE_NULL, // const void* pNext;
1282 m_outBufferAlloc->getMemory(), // VkDeviceMemory mem;
1283 0ull, // VkDeviceSize offset;
1284 m_outBufferAllocSize, // VkDeviceSize size;
1287 VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
1291 return tcu::TestStatus::pass("All values OK");
1293 return tcu::TestStatus::fail("Invalid value(s) found");
1296 bool BufferAccessInstance::verifyResult (void)
1298 std::ostringstream logMsg;
1299 tcu::TestLog& log = m_context.getTestContext().getLog();
1300 const bool isReadAccess = !!(m_bufferAccessType == BUFFER_ACCESS_TYPE_READ || m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE);
1301 const void* inDataPtr = m_inBufferAlloc->getHostPtr();
1302 const void* outDataPtr = m_outBufferAlloc->getHostPtr();
1304 deUint32 valueNdx = 0;
1305 const VkDeviceSize maxAccessRange = isReadAccess ? m_inBufferMaxAccessRange : m_outBufferMaxAccessRange;
1307 for (VkDeviceSize offsetInBytes = 0; offsetInBytes < m_outBufferAllocSize; offsetInBytes += 4)
1309 deUint8* outValuePtr = (deUint8*)outDataPtr + offsetInBytes;
1310 const size_t outValueSize = (size_t)min(4, (m_outBufferAllocSize - offsetInBytes));
1312 if (offsetInBytes >= RobustBufferAccessTest::s_numberOfBytesAccessed)
1314 // The shader will only write 16 values into the result buffer. The rest of the values
1315 // should remain unchanged or may be modified if we are writing out of bounds.
1316 if (!isOutBufferValueUnchanged(offsetInBytes, outValueSize)
1317 && (isReadAccess || !isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, 4)))
1319 logMsg << "\nValue " << valueNdx++ << " has been modified with an unknown value: " << *((deUint32 *)outValuePtr);
1325 const deInt32 distanceToOutOfBounds = (deInt32)maxAccessRange - (deInt32)offsetInBytes;
1326 bool isOutOfBoundsAccess = false;
1328 logMsg << "\n" << valueNdx++ << ": ";
1330 logValue(logMsg, outValuePtr, m_bufferFormat, outValueSize);
1332 if (m_accessOutOfBackingMemory)
1334 isOutOfBoundsAccess = true;
1338 // Check if the shader operation accessed an operand located less than 16 bytes away
1339 // from the out of bounds address.
1341 deUint32 operandSize = 0;
1343 switch (m_shaderType)
1345 case SHADER_TYPE_SCALAR_COPY:
1346 operandSize = 4; // Size of scalar
1349 case SHADER_TYPE_VECTOR_COPY:
1350 operandSize = 4 * ((m_bufferFormat == vk::VK_FORMAT_R64_UINT || m_bufferFormat == vk::VK_FORMAT_R64_SINT) ? 8 : 4);// Size of vec4
1353 case SHADER_TYPE_MATRIX_COPY:
1354 operandSize = 4 * 16; // Size of mat4
1357 case SHADER_TYPE_TEXEL_COPY:
1358 operandSize = mapVkFormat(m_bufferFormat).getPixelSize();
1365 isOutOfBoundsAccess = (maxAccessRange < 16)
1366 || (((offsetInBytes / operandSize + 1) * operandSize) > (maxAccessRange - 16));
1369 if (isOutOfBoundsAccess)
1371 logMsg << " (out of bounds " << (isReadAccess ? "read": "write") << ")";
1373 const bool isValuePartiallyOutOfBounds = ((distanceToOutOfBounds > 0) && ((deUint32)distanceToOutOfBounds < 4));
1374 bool isValidValue = false;
1376 if (isValuePartiallyOutOfBounds && !m_accessOutOfBackingMemory)
1378 // The value is partially out of bounds
1380 bool isOutOfBoundsPartOk = true;
1381 bool isWithinBoundsPartOk = true;
1385 isWithinBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, distanceToOutOfBounds);
1386 isOutOfBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, (deUint8*)outValuePtr + distanceToOutOfBounds , outValueSize - distanceToOutOfBounds);
1390 isWithinBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, distanceToOutOfBounds)
1391 || isOutBufferValueUnchanged(offsetInBytes, distanceToOutOfBounds);
1393 isOutOfBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, (deUint8*)outValuePtr + distanceToOutOfBounds, outValueSize - distanceToOutOfBounds)
1394 || isOutBufferValueUnchanged(offsetInBytes + distanceToOutOfBounds, outValueSize - distanceToOutOfBounds);
1397 logMsg << ", first " << distanceToOutOfBounds << " byte(s) " << (isWithinBoundsPartOk ? "OK": "wrong");
1398 logMsg << ", last " << outValueSize - distanceToOutOfBounds << " byte(s) " << (isOutOfBoundsPartOk ? "OK": "wrong");
1400 isValidValue = isWithinBoundsPartOk && isOutOfBoundsPartOk;
1406 isValidValue = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, outValueSize);
1410 isValidValue = isOutBufferValueUnchanged(offsetInBytes, outValueSize);
1414 // Out of bounds writes may modify values withing the memory ranges bound to the buffer
1415 isValidValue = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, outValueSize);
1418 logMsg << ", OK, written within the memory range bound to the buffer";
1425 // Check if we are satisfying the [0, 0, 0, x] pattern, where x may be either 0 or 1,
1426 // or the maximum representable positive integer value (if the format is integer-based).
1428 const bool canMatchVec4Pattern = (isReadAccess
1429 && !isValuePartiallyOutOfBounds
1430 && (m_shaderType == SHADER_TYPE_VECTOR_COPY || m_shaderType == SHADER_TYPE_TEXEL_COPY)
1431 && ((offsetInBytes / 4 + 1) % 4 == 0 || m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32));
1432 bool matchesVec4Pattern = false;
1434 if (canMatchVec4Pattern)
1436 if (m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1437 matchesVec4Pattern = verifyOutOfBoundsVec4(outValuePtr, m_bufferFormat);
1439 matchesVec4Pattern = verifyOutOfBoundsVec4(reinterpret_cast<deUint32*>(outValuePtr) - 3, m_bufferFormat);
1442 if (!canMatchVec4Pattern || !matchesVec4Pattern)
1444 logMsg << ". Failed: ";
1448 logMsg << "expected value within the buffer range or 0";
1450 if (canMatchVec4Pattern)
1451 logMsg << ", or the [0, 0, 0, x] pattern";
1455 logMsg << "written out of the range";
1462 else // We are within bounds
1466 if (!isExpectedValueFromInBuffer(offsetInBytes, outValuePtr, 4))
1468 logMsg << ", Failed: unexpected value";
1474 // Out of bounds writes may change values within the bounds.
1475 if (!isValueWithinBufferOrZero(inDataPtr, m_inBufferAccessRange, outValuePtr, 4))
1477 logMsg << ", Failed: unexpected value";
1485 log << tcu::TestLog::Message << logMsg.str() << tcu::TestLog::EndMessage;
1490 // BufferReadInstance
1492 BufferReadInstance::BufferReadInstance (Context& context,
1493 Move<VkDevice> device,
1494 #ifndef CTS_USES_VULKANSC
1495 de::MovePtr<vk::DeviceDriver> deviceDriver,
1497 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
1498 #endif // CTS_USES_VULKANSC
1499 ShaderType shaderType,
1500 VkShaderStageFlags shaderStage,
1501 VkFormat bufferFormat,
1502 bool readFromStorage,
1503 VkDeviceSize inBufferAccessRange,
1504 bool accessOutOfBackingMemory,
1505 bool testPipelineRobustness)
1507 : BufferAccessInstance (context, device, deviceDriver, shaderType, shaderStage, bufferFormat,
1508 readFromStorage ? BUFFER_ACCESS_TYPE_READ_FROM_STORAGE : BUFFER_ACCESS_TYPE_READ,
1509 inBufferAccessRange,
1510 RobustBufferAccessTest::s_numberOfBytesAccessed, // outBufferAccessRange
1511 accessOutOfBackingMemory,
1512 testPipelineRobustness)
1516 // BufferWriteInstance
1518 BufferWriteInstance::BufferWriteInstance (Context& context,
1519 Move<VkDevice> device,
1520 #ifndef CTS_USES_VULKANSC
1521 de::MovePtr<vk::DeviceDriver> deviceDriver,
1523 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
1524 #endif // CTS_USES_VULKANSC
1525 ShaderType shaderType,
1526 VkShaderStageFlags shaderStage,
1527 VkFormat bufferFormat,
1528 VkDeviceSize writeBufferAccessRange,
1529 bool accessOutOfBackingMemory,
1530 bool testPipelineRobustness)
1532 : BufferAccessInstance (context, device, deviceDriver, shaderType, shaderStage, bufferFormat,
1533 BUFFER_ACCESS_TYPE_WRITE,
1534 RobustBufferAccessTest::s_numberOfBytesAccessed, // inBufferAccessRange
1535 writeBufferAccessRange,
1536 accessOutOfBackingMemory,
1537 testPipelineRobustness)
1541 // Test node creation functions
1543 static const char* getShaderStageName (VkShaderStageFlagBits shaderStage)
1545 switch (shaderStage)
1547 case VK_SHADER_STAGE_VERTEX_BIT: return "vertex";
1548 case VK_SHADER_STAGE_FRAGMENT_BIT: return "fragment";
1549 case VK_SHADER_STAGE_COMPUTE_BIT: return "compute";
1550 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return "tess_control";
1551 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return "tess_eval";
1552 case VK_SHADER_STAGE_GEOMETRY_BIT: return "geometry";
1561 static void addBufferAccessTests (tcu::TestContext& testCtx, tcu::TestCaseGroup* parentNode, bool testPipelineRobustness)
1563 struct BufferRangeConfig
1569 const VkShaderStageFlagBits bufferAccessStages[] =
1571 VK_SHADER_STAGE_VERTEX_BIT,
1572 VK_SHADER_STAGE_FRAGMENT_BIT,
1573 VK_SHADER_STAGE_COMPUTE_BIT,
1576 const VkFormat bufferFormats[] =
1582 VK_FORMAT_R32_SFLOAT
1585 const VkFormat texelBufferFormats[] =
1587 VK_FORMAT_R32G32B32A32_SINT,
1588 VK_FORMAT_R32G32B32A32_UINT,
1589 VK_FORMAT_R32G32B32A32_SFLOAT,
1591 VK_FORMAT_A2B10G10R10_UNORM_PACK32
1594 const BufferRangeConfig bufferRangeConfigs[] =
1596 { "range_1_byte", 1ull },
1597 { "range_3_bytes", 3ull },
1598 { "range_4_bytes", 4ull }, // size of float
1599 { "range_32_bytes", 32ull }, // size of half mat4
1602 const BufferRangeConfig texelBufferRangeConfigs[] =
1604 { "range_1_texel", 1u },
1605 { "range_3_texels", 3u },
1608 const char* shaderTypeNames[SHADER_TYPE_COUNT] =
1616 for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(bufferAccessStages); stageNdx++)
1618 const VkShaderStageFlagBits stage = bufferAccessStages[stageNdx];
1619 de::MovePtr<tcu::TestCaseGroup> stageTests (new tcu::TestCaseGroup(testCtx, getShaderStageName(stage), ""));
1621 for (int shaderTypeNdx = 0; shaderTypeNdx < SHADER_TYPE_COUNT; shaderTypeNdx++)
1623 const VkFormat* formats;
1624 size_t formatsLength;
1625 const BufferRangeConfig* ranges;
1626 size_t rangesLength;
1627 deUint32 rangeMultiplier;
1628 de::MovePtr<tcu::TestCaseGroup> shaderTypeTests (new tcu::TestCaseGroup(testCtx, shaderTypeNames[shaderTypeNdx], ""));
1630 if ((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY)
1632 formats = texelBufferFormats;
1633 formatsLength = DE_LENGTH_OF_ARRAY(texelBufferFormats);
1635 ranges = texelBufferRangeConfigs;
1636 rangesLength = DE_LENGTH_OF_ARRAY(texelBufferRangeConfigs);
1640 formats = bufferFormats;
1641 formatsLength = DE_LENGTH_OF_ARRAY(bufferFormats);
1643 ranges = bufferRangeConfigs;
1644 rangesLength = DE_LENGTH_OF_ARRAY(bufferRangeConfigs);
1647 for (size_t formatNdx = 0; formatNdx < formatsLength; formatNdx++)
1649 const VkFormat bufferFormat = formats[formatNdx];
1651 rangeMultiplier = ((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY) ? mapVkFormat(bufferFormat).getPixelSize() : 1;
1653 if (!isFloatFormat(bufferFormat) && ((ShaderType)shaderTypeNdx) == SHADER_TYPE_MATRIX_COPY)
1655 // Use SHADER_TYPE_MATRIX_COPY with floating-point formats only
1659 // Avoid too much duplication by excluding certain test cases
1660 if (testPipelineRobustness &&
1661 !(bufferFormat == VK_FORMAT_R32_UINT || bufferFormat == VK_FORMAT_R64_SINT || bufferFormat == VK_FORMAT_R32_SFLOAT || bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32))
1666 const std::string formatName = getFormatName(bufferFormat);
1667 de::MovePtr<tcu::TestCaseGroup> formatTests (new tcu::TestCaseGroup(testCtx, de::toLower(formatName.substr(10)).c_str(), ""));
1669 de::MovePtr<tcu::TestCaseGroup> uboReadTests (new tcu::TestCaseGroup(testCtx, "oob_uniform_read", ""));
1670 de::MovePtr<tcu::TestCaseGroup> ssboReadTests (new tcu::TestCaseGroup(testCtx, "oob_storage_read", ""));
1671 de::MovePtr<tcu::TestCaseGroup> ssboWriteTests (new tcu::TestCaseGroup(testCtx, "oob_storage_write", ""));
1673 for (size_t rangeNdx = 0; rangeNdx < rangesLength; rangeNdx++)
1675 const BufferRangeConfig& rangeConfig = ranges[rangeNdx];
1676 const VkDeviceSize rangeInBytes = rangeConfig.range * rangeMultiplier;
1678 uboReadTests->addChild(new RobustBufferReadTest(testCtx, rangeConfig.name, "", stage, (ShaderType)shaderTypeNdx, bufferFormat, testPipelineRobustness, rangeInBytes, false, false));
1680 // Avoid too much duplication by excluding certain test cases
1681 if (!testPipelineRobustness)
1682 ssboReadTests->addChild(new RobustBufferReadTest(testCtx, rangeConfig.name, "", stage, (ShaderType)shaderTypeNdx, bufferFormat, testPipelineRobustness, rangeInBytes, true, false));
1684 ssboWriteTests->addChild(new RobustBufferWriteTest(testCtx, rangeConfig.name, "", stage, (ShaderType)shaderTypeNdx, bufferFormat, testPipelineRobustness, rangeInBytes, false));
1688 formatTests->addChild(uboReadTests.release());
1689 formatTests->addChild(ssboReadTests.release());
1690 formatTests->addChild(ssboWriteTests.release());
1692 shaderTypeTests->addChild(formatTests.release());
1695 // Read/write out of the memory that backs the buffer
1697 de::MovePtr<tcu::TestCaseGroup> outOfAllocTests (new tcu::TestCaseGroup(testCtx, "out_of_alloc", ""));
1699 const VkFormat format = (((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY ) ? VK_FORMAT_R32G32B32A32_SFLOAT : VK_FORMAT_R32_SFLOAT);
1701 outOfAllocTests->addChild(new RobustBufferReadTest(testCtx, "oob_uniform_read", "", stage, (ShaderType)shaderTypeNdx, format, testPipelineRobustness, 16, false, true));
1703 // Avoid too much duplication by excluding certain test cases
1704 if (!testPipelineRobustness)
1705 outOfAllocTests->addChild(new RobustBufferReadTest(testCtx, "oob_storage_read", "", stage, (ShaderType)shaderTypeNdx, format, testPipelineRobustness, 16, true, true));
1707 outOfAllocTests->addChild(new RobustBufferWriteTest(testCtx, "oob_storage_write", "", stage, (ShaderType)shaderTypeNdx, format, testPipelineRobustness, 16, true));
1709 shaderTypeTests->addChild(outOfAllocTests.release());
1712 stageTests->addChild(shaderTypeTests.release());
1714 parentNode->addChild(stageTests.release());
1718 tcu::TestCaseGroup* createBufferAccessTests (tcu::TestContext& testCtx)
1720 de::MovePtr<tcu::TestCaseGroup> bufferAccessTests (new tcu::TestCaseGroup(testCtx, "buffer_access", ""));
1722 addBufferAccessTests(testCtx, bufferAccessTests.get(), false);
1724 return bufferAccessTests.release();
1727 #ifndef CTS_USES_VULKANSC
1728 tcu::TestCaseGroup* createPipelineRobustnessBufferAccessTests (tcu::TestContext& testCtx)
1730 de::MovePtr<tcu::TestCaseGroup> bufferAccessTests (new tcu::TestCaseGroup(testCtx, "pipeline_robustness_buffer_access", ""));
1731 addBufferAccessTests(testCtx, bufferAccessTests.get(), true);
1733 return bufferAccessTests.release();