1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 Imagination Technologies Ltd.
7  *
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
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  *//*!
21  * \file
22  * \brief Robust buffer access tests for uniform/storage buffers and
23  *        uniform/storage texel buffers.
24  *//*--------------------------------------------------------------------*/
25 
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"
34 #include "vkRef.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "tcuTestLog.hpp"
38 
39 #include <limits>
40 #include <sstream>
41 
42 namespace vkt
43 {
44 namespace robustness
45 {
46 
47 using namespace vk;
48 
49 enum ShaderType
50 {
51     SHADER_TYPE_MATRIX_COPY,
52     SHADER_TYPE_VECTOR_COPY,
53     SHADER_TYPE_VECTOR_MEMBER_COPY,
54     SHADER_TYPE_SCALAR_COPY,
55     SHADER_TYPE_TEXEL_COPY,
56 
57     SHADER_TYPE_COUNT
58 };
59 
60 enum BufferAccessType
61 {
62     BUFFER_ACCESS_TYPE_READ,
63     BUFFER_ACCESS_TYPE_READ_FROM_STORAGE,
64     BUFFER_ACCESS_TYPE_WRITE,
65 };
66 
min(VkDeviceSize a,VkDeviceSize b)67 static VkDeviceSize min(VkDeviceSize a, VkDeviceSize b)
68 {
69     return (a < b) ? a : b;
70 }
71 
72 class RobustBufferAccessTest : public vkt::TestCase
73 {
74 public:
75     static const uint32_t s_testArraySize;
76     static const uint32_t s_testVectorSize;
77     static const uint32_t s_numberOfBytesAccessed;
78     static const uint32_t s_numberOfVectorBytesAccessed;
79 
80     RobustBufferAccessTest(tcu::TestContext &testContext, const std::string &name, VkShaderStageFlags shaderStage,
81                            ShaderType shaderType, VkFormat bufferFormat, bool testPipelineRobustness);
82 
~RobustBufferAccessTest(void)83     virtual ~RobustBufferAccessTest(void)
84     {
85     }
86 
87     virtual void checkSupport(Context &context) const;
88 
getNumberOfBytesAccesssed(ShaderType shaderType)89     static uint32_t getNumberOfBytesAccesssed(ShaderType shaderType)
90     {
91         return shaderType == SHADER_TYPE_VECTOR_MEMBER_COPY ? s_numberOfVectorBytesAccessed : s_numberOfBytesAccessed;
92     }
93 
94 private:
95     static void genBufferShaderAccess(ShaderType shaderType, VkFormat bufferFormat, bool readFromStorage,
96                                       std::ostringstream &bufferDefinition, std::ostringstream &bufferUse);
97 
98     static void genTexelBufferShaderAccess(VkFormat bufferFormat, std::ostringstream &bufferDefinition,
99                                            std::ostringstream &bufferUse, bool readFromStorage);
100 
101 protected:
102     bool is64BitsTest(void) const;
103     bool isVertexTest(void) const;
104     bool isFragmentTest(void) const;
105 
106     static void initBufferAccessPrograms(SourceCollections &programCollection, VkShaderStageFlags shaderStage,
107                                          ShaderType shaderType, VkFormat bufferFormat, bool readFromStorage);
108 
109     const VkShaderStageFlags m_shaderStage;
110     const ShaderType m_shaderType;
111     const VkFormat m_bufferFormat;
112     const bool m_testPipelineRobustness;
113 };
114 
115 class RobustBufferReadTest : public RobustBufferAccessTest
116 {
117 public:
118     RobustBufferReadTest(tcu::TestContext &testContext, const std::string &name, VkShaderStageFlags shaderStage,
119                          ShaderType shaderType, VkFormat bufferFormat, bool testPipelineRobustness,
120                          VkDeviceSize readAccessRange, bool readFromStorage, bool accessOutOfBackingMemory);
121 
~RobustBufferReadTest(void)122     virtual ~RobustBufferReadTest(void)
123     {
124     }
125 
126     virtual void initPrograms(SourceCollections &programCollection) const;
127     virtual TestInstance *createInstance(Context &context) const;
128 
129 private:
130     const bool m_readFromStorage;
131     const VkDeviceSize m_readAccessRange;
132     const bool m_accessOutOfBackingMemory;
133 };
134 
135 class RobustBufferWriteTest : public RobustBufferAccessTest
136 {
137 public:
138     RobustBufferWriteTest(tcu::TestContext &testContext, const std::string &name, VkShaderStageFlags shaderStage,
139                           ShaderType shaderType, VkFormat bufferFormat, bool testPipelineRobustness,
140                           VkDeviceSize writeAccessRange, bool accessOutOfBackingMemory);
141 
~RobustBufferWriteTest(void)142     virtual ~RobustBufferWriteTest(void)
143     {
144     }
145 
146     virtual void initPrograms(SourceCollections &programCollection) const;
147     virtual TestInstance *createInstance(Context &context) const;
148 
149 private:
150     const VkDeviceSize m_writeAccessRange;
151     const bool m_accessOutOfBackingMemory;
152 };
153 
154 class BufferAccessInstance : public vkt::TestInstance
155 {
156 public:
157     BufferAccessInstance(Context &context, Move<VkDevice> device,
158 #ifndef CTS_USES_VULKANSC
159                          de::MovePtr<vk::DeviceDriver> deviceDriver,
160 #else
161                          de::MovePtr<CustomInstance> customInstance,
162                          de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
163 #endif // CTS_USES_VULKANSC
164                          ShaderType shaderType, VkShaderStageFlags shaderStage, VkFormat bufferFormat,
165                          BufferAccessType bufferAccessType, VkDeviceSize inBufferAccessRange,
166                          VkDeviceSize outBufferAccessRange, bool accessOutOfBackingMemory, bool testPipelineRobustness);
167 
168     virtual ~BufferAccessInstance(void);
169 
170     virtual tcu::TestStatus iterate(void);
171 
172     virtual bool verifyResult(void);
173 
174 private:
175     bool isExpectedValueFromInBuffer(VkDeviceSize offsetInBytes, const void *valuePtr, VkDeviceSize valueSize);
176     bool isOutBufferValueUnchanged(VkDeviceSize offsetInBytes, VkDeviceSize valueSize);
177 
178 protected:
179 #ifndef CTS_USES_VULKANSC
180     Move<VkDevice> m_device;
181     de::MovePtr<vk::DeviceDriver> m_deviceDriver;
182 #else
183     // Construction needs to happen in this exact order to ensure proper resource destruction
184     de::MovePtr<CustomInstance> m_customInstance;
185     Move<VkDevice> m_device;
186     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> m_deviceDriver;
187 #endif // CTS_USES_VULKANSC
188 
189     de::MovePtr<TestEnvironment> m_testEnvironment;
190 
191     const ShaderType m_shaderType;
192     const VkShaderStageFlags m_shaderStage;
193 
194     const VkFormat m_bufferFormat;
195     const BufferAccessType m_bufferAccessType;
196 
197     const VkDeviceSize m_inBufferAccessRange;
198     Move<VkBuffer> m_inBuffer;
199     de::MovePtr<Allocation> m_inBufferAlloc;
200     VkDeviceSize m_inBufferAllocSize;
201     VkDeviceSize m_inBufferMaxAccessRange;
202 
203     const VkDeviceSize m_outBufferAccessRange;
204     Move<VkBuffer> m_outBuffer;
205     de::MovePtr<Allocation> m_outBufferAlloc;
206     VkDeviceSize m_outBufferAllocSize;
207     VkDeviceSize m_outBufferMaxAccessRange;
208 
209     Move<VkBuffer> m_indicesBuffer;
210     de::MovePtr<Allocation> m_indicesBufferAlloc;
211 
212     Move<VkDescriptorPool> m_descriptorPool;
213     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
214     Move<VkDescriptorSet> m_descriptorSet;
215 
216     Move<VkFence> m_fence;
217     VkQueue m_queue;
218 
219     // Used when m_shaderStage == VK_SHADER_STAGE_VERTEX_BIT
220     Move<VkBuffer> m_vertexBuffer;
221     de::MovePtr<Allocation> m_vertexBufferAlloc;
222 
223     // Used when m_shaderType == SHADER_TYPE_TEXEL_COPY
224     Move<VkBufferView> m_inTexelBufferView;
225     Move<VkBufferView> m_outTexelBufferView;
226 
227     const bool m_accessOutOfBackingMemory;
228     const bool m_testPipelineRobustness;
229 };
230 
231 class BufferReadInstance : public BufferAccessInstance
232 {
233 public:
234     BufferReadInstance(Context &context, Move<VkDevice> device,
235 #ifndef CTS_USES_VULKANSC
236                        de::MovePtr<vk::DeviceDriver> deviceDriver,
237 #else
238                        de::MovePtr<CustomInstance> customInstance,
239                        de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
240 #endif // CTS_USES_VULKANSC
241                        ShaderType shaderType, VkShaderStageFlags shaderStage, VkFormat bufferFormat,
242                        bool readFromStorage, VkDeviceSize inBufferAccessRange, bool accessOutOfBackingMemory,
243                        bool testPipelineRobustness);
244 
~BufferReadInstance(void)245     virtual ~BufferReadInstance(void)
246     {
247     }
248 
249 private:
250 };
251 
252 class BufferWriteInstance : public BufferAccessInstance
253 {
254 public:
255     BufferWriteInstance(Context &context, Move<VkDevice> device,
256 #ifndef CTS_USES_VULKANSC
257                         de::MovePtr<vk::DeviceDriver> deviceDriver,
258 #else
259                         de::MovePtr<CustomInstance> customInstance,
260                         de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
261 #endif // CTS_USES_VULKANSC
262                         ShaderType shaderType, VkShaderStageFlags shaderStage, VkFormat bufferFormat,
263                         VkDeviceSize writeBufferAccessRange, bool accessOutOfBackingMemory,
264                         bool testPipelineRobustness);
265 
~BufferWriteInstance(void)266     virtual ~BufferWriteInstance(void)
267     {
268     }
269 };
270 
271 // RobustBufferAccessTest
272 
273 const uint32_t RobustBufferAccessTest::s_testArraySize  = 128; // Fit within minimum required maxUniformBufferRange
274 const uint32_t RobustBufferAccessTest::s_testVectorSize = 4;   // vec4
275 const uint32_t RobustBufferAccessTest::s_numberOfBytesAccessed       = (uint32_t)(16 * sizeof(float)); // size of mat4
276 const uint32_t RobustBufferAccessTest::s_numberOfVectorBytesAccessed = (uint32_t)(4 * sizeof(float));  // size of vec4
277 
RobustBufferAccessTest(tcu::TestContext & testContext,const std::string & name,VkShaderStageFlags shaderStage,ShaderType shaderType,VkFormat bufferFormat,bool testPipelineRobustness)278 RobustBufferAccessTest::RobustBufferAccessTest(tcu::TestContext &testContext, const std::string &name,
279                                                VkShaderStageFlags shaderStage, ShaderType shaderType,
280                                                VkFormat bufferFormat, bool testPipelineRobustness)
281     : vkt::TestCase(testContext, name)
282     , m_shaderStage(shaderStage)
283     , m_shaderType(shaderType)
284     , m_bufferFormat(bufferFormat)
285     , m_testPipelineRobustness(testPipelineRobustness)
286 {
287     DE_ASSERT(m_shaderStage == VK_SHADER_STAGE_VERTEX_BIT || m_shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT ||
288               m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT);
289 }
290 
checkSupport(Context & context) const291 void RobustBufferAccessTest::checkSupport(Context &context) const
292 {
293     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
294         !context.getDeviceFeatures().robustBufferAccess)
295         TCU_THROW(NotSupportedError,
296                   "VK_KHR_portability_subset: robustBufferAccess not supported by this implementation");
297 
298     if (is64BitsTest())
299         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_INT64);
300 
301     if (isVertexTest())
302         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
303 
304     if (isFragmentTest())
305         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
306 }
307 
genBufferShaderAccess(ShaderType shaderType,VkFormat bufferFormat,bool readFromStorage,std::ostringstream & bufferDefinition,std::ostringstream & bufferUse)308 void RobustBufferAccessTest::genBufferShaderAccess(ShaderType shaderType, VkFormat bufferFormat, bool readFromStorage,
309                                                    std::ostringstream &bufferDefinition, std::ostringstream &bufferUse)
310 {
311     if (shaderType == SHADER_TYPE_VECTOR_MEMBER_COPY)
312     {
313         std::string typePrefixStr;
314 
315         if (isUintFormat(bufferFormat))
316         {
317             typePrefixStr = "u";
318         }
319         else if (isIntFormat(bufferFormat))
320         {
321             typePrefixStr = "i";
322         }
323         else
324         {
325             typePrefixStr = "";
326         }
327 
328         typePrefixStr += (bufferFormat == vk::VK_FORMAT_R64_UINT || bufferFormat == vk::VK_FORMAT_R64_SINT) ? "64" : "";
329 
330         bufferDefinition << "layout(binding = 0, " << (readFromStorage ? "std430" : "std140") << ") "
331                          << (readFromStorage ? "buffer readonly" : "uniform")
332                          << " InBuffer\n"
333                             "{\n"
334                             "    "
335                          << typePrefixStr
336                          << "vec4 inVec;\n"
337                             "};\n\n";
338 
339         bufferDefinition << "layout(binding = 1, std430) buffer OutBuffer\n"
340                             "{\n"
341                             "    "
342                          << typePrefixStr
343                          << "vec4 outVec;\n"
344                             "};\n\n";
345 
346         bufferDefinition << "layout(binding = 2, std140) uniform Indices\n"
347                             "{\n"
348                             "    int inIndex;\n"
349                             "    int outIndex;\n"
350                             "};\n\n";
351 
352         bufferUse << "    outVec[outIndex] = inVec[inIndex];\n"
353                      "    outVec[outIndex + 1] = inVec[inIndex + 1];\n"
354                      "    outVec[outIndex + 2] = inVec[inIndex + 2];\n"
355                      "    outVec[outIndex + 3] = inVec[inIndex + 3];\n";
356     }
357     else if (isFloatFormat(bufferFormat))
358     {
359         bufferDefinition << "layout(binding = 0, " << (readFromStorage ? "std430" : "std140") << ") "
360                          << (readFromStorage ? "buffer" : "uniform")
361                          << " InBuffer\n"
362                             "{\n"
363                             "    mat4 inMatrix["
364                          << s_testArraySize
365                          << "];\n"
366                             "};\n\n";
367 
368         bufferDefinition << "layout(binding = 1, std430) buffer OutBuffer\n"
369                             "{\n"
370                             "    mat4 outMatrix["
371                          << s_testArraySize
372                          << "];\n"
373                             "};\n\n";
374 
375         bufferDefinition << "layout(binding = 2, std140) uniform Indices\n"
376                             "{\n"
377                             "    int inIndex;\n"
378                             "    int outIndex;\n"
379                             "};\n\n";
380 
381         switch (shaderType)
382         {
383         case SHADER_TYPE_MATRIX_COPY:
384             bufferUse << "    mat4 tmp = inMatrix[inIndex];\n"
385                          "    outMatrix[outIndex] = tmp;\n";
386             break;
387 
388         case SHADER_TYPE_VECTOR_COPY:
389             bufferUse << "    outMatrix[outIndex][0] = inMatrix[inIndex][0];\n"
390                          "    outMatrix[outIndex][1] = inMatrix[inIndex][1];\n"
391                          "    outMatrix[outIndex][2] = inMatrix[inIndex][2];\n"
392                          "    outMatrix[outIndex][3] = inMatrix[inIndex][3];\n";
393             break;
394 
395         case SHADER_TYPE_SCALAR_COPY:
396             bufferUse << "    outMatrix[outIndex][0][0] = inMatrix[inIndex][0][0];\n"
397                          "    outMatrix[outIndex][0][1] = inMatrix[inIndex][0][1];\n"
398                          "    outMatrix[outIndex][0][2] = inMatrix[inIndex][0][2];\n"
399                          "    outMatrix[outIndex][0][3] = inMatrix[inIndex][0][3];\n"
400 
401                          "    outMatrix[outIndex][1][0] = inMatrix[inIndex][1][0];\n"
402                          "    outMatrix[outIndex][1][1] = inMatrix[inIndex][1][1];\n"
403                          "    outMatrix[outIndex][1][2] = inMatrix[inIndex][1][2];\n"
404                          "    outMatrix[outIndex][1][3] = inMatrix[inIndex][1][3];\n"
405 
406                          "    outMatrix[outIndex][2][0] = inMatrix[inIndex][2][0];\n"
407                          "    outMatrix[outIndex][2][1] = inMatrix[inIndex][2][1];\n"
408                          "    outMatrix[outIndex][2][2] = inMatrix[inIndex][2][2];\n"
409                          "    outMatrix[outIndex][2][3] = inMatrix[inIndex][2][3];\n"
410 
411                          "    outMatrix[outIndex][3][0] = inMatrix[inIndex][3][0];\n"
412                          "    outMatrix[outIndex][3][1] = inMatrix[inIndex][3][1];\n"
413                          "    outMatrix[outIndex][3][2] = inMatrix[inIndex][3][2];\n"
414                          "    outMatrix[outIndex][3][3] = inMatrix[inIndex][3][3];\n";
415             break;
416 
417         default:
418             DE_ASSERT(false);
419         }
420     }
421     else
422     {
423         std::string typePrefixStr;
424 
425         if (isUintFormat(bufferFormat))
426         {
427             typePrefixStr = "u";
428         }
429         else if (isIntFormat(bufferFormat))
430         {
431             typePrefixStr = "i";
432         }
433         else
434         {
435             DE_ASSERT(false);
436         }
437 
438         typePrefixStr += (bufferFormat == vk::VK_FORMAT_R64_UINT || bufferFormat == vk::VK_FORMAT_R64_SINT) ? "64" : "";
439 
440         bufferDefinition << "layout(binding = 0, " << (readFromStorage ? "std430" : "std140") << ") "
441                          << (readFromStorage ? "buffer readonly" : "uniform")
442                          << " InBuffer\n"
443                             "{\n"
444                             "    "
445                          << typePrefixStr << "vec4 inVecs[" << s_testArraySize
446                          << "][4];\n"
447                             "};\n\n";
448 
449         bufferDefinition << "layout(binding = 1, std430) buffer OutBuffer\n"
450                             "{\n"
451                             "    "
452                          << typePrefixStr << "vec4 outVecs[" << s_testArraySize
453                          << "][4];\n"
454                             "};\n\n";
455 
456         bufferDefinition << "layout(binding = 2, std140) uniform Indices\n"
457                             "{\n"
458                             "    int inIndex;\n"
459                             "    int outIndex;\n"
460                             "};\n\n";
461 
462         switch (shaderType)
463         {
464         case SHADER_TYPE_MATRIX_COPY:
465             // Shader type not supported for integer types.
466             DE_ASSERT(false);
467             break;
468 
469         case SHADER_TYPE_VECTOR_COPY:
470             bufferUse << "    outVecs[outIndex][0] = inVecs[inIndex][0];\n"
471                          "    outVecs[outIndex][1] = inVecs[inIndex][1];\n"
472                          "    outVecs[outIndex][2] = inVecs[inIndex][2];\n"
473                          "    outVecs[outIndex][3] = inVecs[inIndex][3];\n";
474             break;
475 
476         case SHADER_TYPE_SCALAR_COPY:
477             bufferUse << "    outVecs[outIndex][0][0] = inVecs[inIndex][0][0];\n"
478                          "    outVecs[outIndex][0][1] = inVecs[inIndex][0][1];\n"
479                          "    outVecs[outIndex][0][2] = inVecs[inIndex][0][2];\n"
480                          "    outVecs[outIndex][0][3] = inVecs[inIndex][0][3];\n"
481 
482                          "    outVecs[outIndex][1][0] = inVecs[inIndex][1][0];\n"
483                          "    outVecs[outIndex][1][1] = inVecs[inIndex][1][1];\n"
484                          "    outVecs[outIndex][1][2] = inVecs[inIndex][1][2];\n"
485                          "    outVecs[outIndex][1][3] = inVecs[inIndex][1][3];\n"
486 
487                          "    outVecs[outIndex][2][0] = inVecs[inIndex][2][0];\n"
488                          "    outVecs[outIndex][2][1] = inVecs[inIndex][2][1];\n"
489                          "    outVecs[outIndex][2][2] = inVecs[inIndex][2][2];\n"
490                          "    outVecs[outIndex][2][3] = inVecs[inIndex][2][3];\n"
491 
492                          "    outVecs[outIndex][3][0] = inVecs[inIndex][3][0];\n"
493                          "    outVecs[outIndex][3][1] = inVecs[inIndex][3][1];\n"
494                          "    outVecs[outIndex][3][2] = inVecs[inIndex][3][2];\n"
495                          "    outVecs[outIndex][3][3] = inVecs[inIndex][3][3];\n";
496             break;
497 
498         default:
499             DE_ASSERT(false);
500         }
501     }
502 }
503 
genTexelBufferShaderAccess(VkFormat bufferFormat,std::ostringstream & bufferDefinition,std::ostringstream & bufferUse,bool readFromStorage)504 void RobustBufferAccessTest::genTexelBufferShaderAccess(VkFormat bufferFormat, std::ostringstream &bufferDefinition,
505                                                         std::ostringstream &bufferUse, bool readFromStorage)
506 {
507     const char *layoutTypeStr;
508     const char *inTexelBufferTypeStr;
509     const char *outTexelBufferTypeStr;
510     const uint32_t texelSize = mapVkFormat(bufferFormat).getPixelSize();
511 
512     if (isFloatFormat(bufferFormat))
513     {
514         layoutTypeStr         = "rgba32f";
515         inTexelBufferTypeStr  = readFromStorage ? "imageBuffer" : "textureBuffer";
516         outTexelBufferTypeStr = "imageBuffer";
517     }
518     else if (isUintFormat(bufferFormat))
519     {
520         layoutTypeStr         = "rgba32ui";
521         inTexelBufferTypeStr  = readFromStorage ? "uimageBuffer" : "utextureBuffer";
522         outTexelBufferTypeStr = "uimageBuffer";
523     }
524     else if (isIntFormat(bufferFormat))
525     {
526         layoutTypeStr         = "rgba32i";
527         inTexelBufferTypeStr  = readFromStorage ? "iimageBuffer" : "itextureBuffer";
528         outTexelBufferTypeStr = "iimageBuffer";
529     }
530     else if (bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
531     {
532         layoutTypeStr         = "rgb10_a2";
533         inTexelBufferTypeStr  = readFromStorage ? "imageBuffer" : "textureBuffer";
534         outTexelBufferTypeStr = "imageBuffer";
535     }
536     else
537     {
538         TCU_THROW(NotSupportedError, (std::string("Unsupported format: ") + getFormatName(bufferFormat)).c_str());
539     }
540 
541     bufferDefinition << "layout(set = 0, binding = 0" << ((readFromStorage) ? (std::string(", ") + layoutTypeStr) : "")
542                      << ") uniform highp " << ((readFromStorage) ? "readonly " : "") << inTexelBufferTypeStr
543                      << " inImage;\n";
544 
545     bufferDefinition << "layout(set = 0, binding = 1, " << layoutTypeStr << ") uniform highp writeonly "
546                      << outTexelBufferTypeStr << " outImage;\n";
547 
548     bufferDefinition << "layout(binding = 2, std140) uniform Offsets\n"
549                         "{\n"
550                         "    int inOffset;\n"
551                         "    int outOffset;\n"
552                         "};\n\n";
553 
554     bufferUse << "    for (int i = 0; i < " << (s_numberOfBytesAccessed / texelSize) << "; i++)\n"
555               << "    {\n"
556               << "        imageStore(outImage, outOffset + i, " << (readFromStorage ? "imageLoad" : "texelFetch")
557               << "(inImage, inOffset + i));\n"
558               << "    }\n";
559 }
560 
is64BitsTest(void) const561 bool RobustBufferAccessTest::is64BitsTest(void) const
562 {
563     return (m_bufferFormat == VK_FORMAT_R64_SINT || m_bufferFormat == VK_FORMAT_R64_UINT);
564 }
565 
isVertexTest(void) const566 bool RobustBufferAccessTest::isVertexTest(void) const
567 {
568     return ((m_shaderStage & VK_SHADER_STAGE_VERTEX_BIT) != 0u);
569 }
570 
isFragmentTest(void) const571 bool RobustBufferAccessTest::isFragmentTest(void) const
572 {
573     return ((m_shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0u);
574 }
575 
initBufferAccessPrograms(SourceCollections & programCollection,VkShaderStageFlags shaderStage,ShaderType shaderType,VkFormat bufferFormat,bool readFromStorage)576 void RobustBufferAccessTest::initBufferAccessPrograms(SourceCollections &programCollection,
577                                                       VkShaderStageFlags shaderStage, ShaderType shaderType,
578                                                       VkFormat bufferFormat, bool readFromStorage)
579 {
580     std::ostringstream bufferDefinition;
581     std::ostringstream bufferUse;
582     std::string extensions;
583 
584     if (bufferFormat == vk::VK_FORMAT_R64_UINT || bufferFormat == vk::VK_FORMAT_R64_SINT)
585     {
586         extensions = "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n";
587     }
588 
589     if (shaderType != SHADER_TYPE_TEXEL_COPY)
590     {
591         genBufferShaderAccess(shaderType, bufferFormat, readFromStorage, bufferDefinition, bufferUse);
592     }
593 
594     if (shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
595     {
596         std::ostringstream computeShaderSource;
597 
598         if (shaderType == SHADER_TYPE_TEXEL_COPY)
599             genTexelBufferShaderAccess(bufferFormat, bufferDefinition, bufferUse, readFromStorage);
600 
601         computeShaderSource << "#version 440\n"
602                                "#extension GL_EXT_texture_buffer : require\n"
603                             << extensions
604                             << "precision highp float;\n"
605                                "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
606                             << bufferDefinition.str()
607                             << "void main (void)\n"
608                                "{\n"
609                             << bufferUse.str() << "}\n";
610         programCollection.glslSources.add("compute") << glu::ComputeSource(computeShaderSource.str());
611     }
612     else
613     {
614         std::ostringstream vertexShaderSource;
615         std::ostringstream fragmentShaderSource;
616 
617         if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
618         {
619             if (shaderType == SHADER_TYPE_TEXEL_COPY)
620                 genTexelBufferShaderAccess(bufferFormat, bufferDefinition, bufferUse, readFromStorage);
621 
622             vertexShaderSource << "#version 440\n"
623                                   "#extension GL_EXT_texture_buffer : require\n"
624                                << extensions
625                                << "precision highp float;\n"
626                                   "layout(location = 0) in vec4 position;\n\n"
627                                << bufferDefinition.str()
628                                << "\n"
629                                   "out gl_PerVertex {\n"
630                                   "    vec4 gl_Position;\n"
631                                   "};\n\n"
632                                   "void main (void)\n"
633                                   "{\n"
634                                << bufferUse.str()
635                                << "    gl_Position = position;\n"
636                                   "}\n";
637         }
638         else
639         {
640             vertexShaderSource << "#version 440\n"
641                                   "precision highp float;\n"
642                                   "layout(location = 0) in vec4 position;\n\n"
643                                   "out gl_PerVertex {\n"
644                                   "    vec4 gl_Position;\n"
645                                   "};\n\n"
646                                   "void main (void)\n"
647                                   "{\n"
648                                   "    gl_Position = position;\n"
649                                   "}\n";
650         }
651 
652         programCollection.glslSources.add("vertex") << glu::VertexSource(vertexShaderSource.str());
653 
654         if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
655         {
656             if (shaderType == SHADER_TYPE_TEXEL_COPY)
657                 genTexelBufferShaderAccess(bufferFormat, bufferDefinition, bufferUse, readFromStorage);
658 
659             fragmentShaderSource << "#version 440\n"
660                                     "#extension GL_EXT_texture_buffer : require\n"
661                                  << extensions
662                                  << "precision highp float;\n"
663                                     "layout(location = 0) out vec4 fragColor;\n"
664                                  << bufferDefinition.str()
665                                  << "void main (void)\n"
666                                     "{\n"
667                                  << bufferUse.str()
668                                  << "    fragColor = vec4(1.0);\n"
669                                     "}\n";
670         }
671         else
672         {
673             fragmentShaderSource << "#version 440\n"
674                                     "precision highp float;\n"
675                                     "layout(location = 0) out vec4 fragColor;\n\n"
676                                     "void main (void)\n"
677                                     "{\n"
678                                     "    fragColor = vec4(1.0);\n"
679                                     "}\n";
680         }
681 
682         programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentShaderSource.str());
683     }
684 }
685 
686 // RobustBufferReadTest
687 
RobustBufferReadTest(tcu::TestContext & testContext,const std::string & name,VkShaderStageFlags shaderStage,ShaderType shaderType,VkFormat bufferFormat,bool testPipelineRobustness,VkDeviceSize readAccessRange,bool readFromStorage,bool accessOutOfBackingMemory)688 RobustBufferReadTest::RobustBufferReadTest(tcu::TestContext &testContext, const std::string &name,
689                                            VkShaderStageFlags shaderStage, ShaderType shaderType, VkFormat bufferFormat,
690                                            bool testPipelineRobustness, VkDeviceSize readAccessRange,
691                                            bool readFromStorage, bool accessOutOfBackingMemory)
692     : RobustBufferAccessTest(testContext, name, shaderStage, shaderType, bufferFormat, testPipelineRobustness)
693     , m_readFromStorage(readFromStorage)
694     , m_readAccessRange(readAccessRange)
695     , m_accessOutOfBackingMemory(accessOutOfBackingMemory)
696 {
697 }
698 
initPrograms(SourceCollections & programCollection) const699 void RobustBufferReadTest::initPrograms(SourceCollections &programCollection) const
700 {
701     initBufferAccessPrograms(programCollection, m_shaderStage, m_shaderType, m_bufferFormat, m_readFromStorage);
702 }
703 
createInstance(Context & context) const704 TestInstance *RobustBufferReadTest::createInstance(Context &context) const
705 {
706     const bool is64BitsTest_   = is64BitsTest();
707     const bool isVertexTest_   = isVertexTest();
708     const bool isFragmentTest_ = isFragmentTest();
709 
710     VkPhysicalDeviceFeatures2 features2 = initVulkanStructure();
711 
712     if (!m_testPipelineRobustness)
713         features2.features.robustBufferAccess = VK_TRUE;
714 
715     if (is64BitsTest_)
716         features2.features.shaderInt64 = VK_TRUE;
717 
718     if (isVertexTest_)
719         features2.features.vertexPipelineStoresAndAtomics = VK_TRUE;
720 
721     if (isFragmentTest_)
722         features2.features.fragmentStoresAndAtomics = VK_TRUE;
723 
724 #ifndef CTS_USES_VULKANSC
725     VkPhysicalDevicePipelineRobustnessFeaturesEXT pipelineRobustnessFeatures = initVulkanStructure();
726     if (m_testPipelineRobustness)
727     {
728         context.requireDeviceFunctionality("VK_EXT_pipeline_robustness");
729 
730         pipelineRobustnessFeatures.pipelineRobustness = VK_TRUE;
731 
732         pipelineRobustnessFeatures.pNext = features2.pNext;
733         features2.pNext                  = &pipelineRobustnessFeatures;
734     }
735 #endif
736 
737     const bool useFeatures2 = (m_testPipelineRobustness || is64BitsTest_ || isVertexTest_ || isFragmentTest_);
738 
739 #ifndef CTS_USES_VULKANSC
740     Move<VkDevice> device = createRobustBufferAccessDevice(context, (useFeatures2 ? &features2 : nullptr));
741     de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(
742         new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion(),
743                          context.getTestContext().getCommandLine()));
744 #else
745     de::MovePtr<CustomInstance> customInstance =
746         de::MovePtr<CustomInstance>(new CustomInstance(createCustomInstanceFromContext(context)));
747     Move<VkDevice> device =
748         createRobustBufferAccessDevice(context, *customInstance, (useFeatures2 ? &features2 : nullptr));
749     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver =
750         de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
751             new DeviceDriverSC(context.getPlatformInterface(), *customInstance, *device,
752                                context.getTestContext().getCommandLine(), context.getResourceInterface(),
753                                context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(),
754                                context.getUsedApiVersion()),
755             vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
756 #endif // CTS_USES_VULKANSC
757 
758     return new BufferReadInstance(context, device,
759 #ifdef CTS_USES_VULKANSC
760                                   customInstance,
761 #endif // CTS_USES_VULKANSC
762                                   deviceDriver, m_shaderType, m_shaderStage, m_bufferFormat, m_readFromStorage,
763                                   m_readAccessRange, m_accessOutOfBackingMemory, m_testPipelineRobustness);
764 }
765 
766 // RobustBufferWriteTest
767 
RobustBufferWriteTest(tcu::TestContext & testContext,const std::string & name,VkShaderStageFlags shaderStage,ShaderType shaderType,VkFormat bufferFormat,bool testPipelineRobustness,VkDeviceSize writeAccessRange,bool accessOutOfBackingMemory)768 RobustBufferWriteTest::RobustBufferWriteTest(tcu::TestContext &testContext, const std::string &name,
769                                              VkShaderStageFlags shaderStage, ShaderType shaderType,
770                                              VkFormat bufferFormat, bool testPipelineRobustness,
771                                              VkDeviceSize writeAccessRange, bool accessOutOfBackingMemory)
772 
773     : RobustBufferAccessTest(testContext, name, shaderStage, shaderType, bufferFormat, testPipelineRobustness)
774     , m_writeAccessRange(writeAccessRange)
775     , m_accessOutOfBackingMemory(accessOutOfBackingMemory)
776 {
777 }
778 
initPrograms(SourceCollections & programCollection) const779 void RobustBufferWriteTest::initPrograms(SourceCollections &programCollection) const
780 {
781     initBufferAccessPrograms(programCollection, m_shaderStage, m_shaderType, m_bufferFormat,
782                              false /* readFromStorage */);
783 }
784 
createInstance(Context & context) const785 TestInstance *RobustBufferWriteTest::createInstance(Context &context) const
786 {
787     const bool is64BitsTest_   = is64BitsTest();
788     const bool isVertexTest_   = isVertexTest();
789     const bool isFragmentTest_ = isFragmentTest();
790 
791     VkPhysicalDeviceFeatures2 features2 = initVulkanStructure();
792 
793     if (!m_testPipelineRobustness)
794         features2.features.robustBufferAccess = VK_TRUE;
795 
796     if (is64BitsTest_)
797         features2.features.shaderInt64 = VK_TRUE;
798 
799     if (isVertexTest_)
800         features2.features.vertexPipelineStoresAndAtomics = VK_TRUE;
801 
802     if (isFragmentTest_)
803         features2.features.fragmentStoresAndAtomics = VK_TRUE;
804 
805 #ifndef CTS_USES_VULKANSC
806     VkPhysicalDevicePipelineRobustnessFeaturesEXT pipelineRobustnessFeatures = initVulkanStructure();
807     if (m_testPipelineRobustness)
808     {
809         context.requireDeviceFunctionality("VK_EXT_pipeline_robustness");
810 
811         const auto &vki           = context.getInstanceInterface();
812         const auto physicalDevice = context.getPhysicalDevice();
813 
814         pipelineRobustnessFeatures.pNext = features2.pNext;
815         features2.pNext                  = &pipelineRobustnessFeatures;
816 
817         vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
818     }
819 #endif
820 
821     const bool useFeatures2 = (m_testPipelineRobustness || is64BitsTest_ || isVertexTest_ || isFragmentTest_);
822 
823 #ifndef CTS_USES_VULKANSC
824     Move<VkDevice> device = createRobustBufferAccessDevice(context, (useFeatures2 ? &features2 : nullptr));
825     de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(
826         new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion(),
827                          context.getTestContext().getCommandLine()));
828 #else
829     de::MovePtr<CustomInstance> customInstance =
830         de::MovePtr<CustomInstance>(new CustomInstance(createCustomInstanceFromContext(context)));
831     Move<VkDevice> device =
832         createRobustBufferAccessDevice(context, *customInstance, (useFeatures2 ? &features2 : nullptr));
833     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver =
834         de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
835             new DeviceDriverSC(context.getPlatformInterface(), *customInstance, *device,
836                                context.getTestContext().getCommandLine(), context.getResourceInterface(),
837                                context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(),
838                                context.getUsedApiVersion()),
839             vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
840 #endif // CTS_USES_VULKANSC
841 
842     return new BufferWriteInstance(context, device,
843 #ifdef CTS_USES_VULKANSC
844                                    customInstance,
845 #endif // CTS_USES_VULKANSC
846                                    deviceDriver, m_shaderType, m_shaderStage, m_bufferFormat, m_writeAccessRange,
847                                    m_accessOutOfBackingMemory, m_testPipelineRobustness);
848 }
849 
850 // BufferAccessInstance
851 
BufferAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,ShaderType shaderType,VkShaderStageFlags shaderStage,VkFormat bufferFormat,BufferAccessType bufferAccessType,VkDeviceSize inBufferAccessRange,VkDeviceSize outBufferAccessRange,bool accessOutOfBackingMemory,bool testPipelineRobustness)852 BufferAccessInstance::BufferAccessInstance(Context &context, Move<VkDevice> device,
853 #ifndef CTS_USES_VULKANSC
854                                            de::MovePtr<vk::DeviceDriver> deviceDriver,
855 #else
856                                            de::MovePtr<CustomInstance> customInstance,
857                                            de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
858 #endif // CTS_USES_VULKANSC
859                                            ShaderType shaderType, VkShaderStageFlags shaderStage, VkFormat bufferFormat,
860                                            BufferAccessType bufferAccessType, VkDeviceSize inBufferAccessRange,
861                                            VkDeviceSize outBufferAccessRange, bool accessOutOfBackingMemory,
862                                            bool testPipelineRobustness)
863     : vkt::TestInstance(context)
864 #ifdef CTS_USES_VULKANSC
865     , m_customInstance(customInstance)
866 #endif // CTS_USES_VULKANSC
867     , m_device(device)
868     , m_deviceDriver(deviceDriver)
869     , m_shaderType(shaderType)
870     , m_shaderStage(shaderStage)
871     , m_bufferFormat(bufferFormat)
872     , m_bufferAccessType(bufferAccessType)
873     , m_inBufferAccessRange(inBufferAccessRange)
874     , m_outBufferAccessRange(outBufferAccessRange)
875     , m_accessOutOfBackingMemory(accessOutOfBackingMemory)
876     , m_testPipelineRobustness(testPipelineRobustness)
877 {
878     const DeviceInterface &vk             = *m_deviceDriver;
879     const auto &vki                       = context.getInstanceInterface();
880     const auto instance                   = context.getInstance();
881     const uint32_t queueFamilyIndex       = context.getUniversalQueueFamilyIndex();
882     const bool isTexelAccess              = !!(m_shaderType == SHADER_TYPE_TEXEL_COPY);
883     const bool readFromStorage            = !!(m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE);
884     const VkPhysicalDevice physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine());
885     SimpleAllocator memAlloc(vk, *m_device, getPhysicalDeviceMemoryProperties(vki, physicalDevice));
886     tcu::TestLog &log = m_context.getTestContext().getLog();
887 
888     uint32_t numberOfBytesAccessed = RobustBufferAccessTest::getNumberOfBytesAccesssed(shaderType);
889     DE_ASSERT(numberOfBytesAccessed % sizeof(uint32_t) == 0);
890     DE_ASSERT(inBufferAccessRange <= numberOfBytesAccessed);
891     DE_ASSERT(outBufferAccessRange <= numberOfBytesAccessed);
892 
893     if (m_bufferFormat == VK_FORMAT_R64_UINT || m_bufferFormat == VK_FORMAT_R64_SINT)
894     {
895         context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
896     }
897 
898     // Check storage support
899     if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
900     {
901         if (!context.getDeviceFeatures().vertexPipelineStoresAndAtomics)
902         {
903             TCU_THROW(NotSupportedError, "Stores not supported in vertex stage");
904         }
905     }
906     else if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
907     {
908         if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
909         {
910             TCU_THROW(NotSupportedError, "Stores not supported in fragment stage");
911         }
912     }
913 
914     // Check format support
915     {
916         VkFormatFeatureFlags requiredFormatFeatures = 0;
917         const VkFormatProperties formatProperties =
918             getPhysicalDeviceFormatProperties(vki, physicalDevice, m_bufferFormat);
919 
920         if (isTexelAccess)
921         {
922             requiredFormatFeatures =
923                 VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
924         }
925 
926         if ((formatProperties.bufferFeatures & requiredFormatFeatures) != requiredFormatFeatures)
927         {
928             TCU_THROW(NotSupportedError,
929                       (std::string("Format cannot be used in uniform and storage") + (isTexelAccess ? " texel" : "") +
930                        " buffers: " + getFormatName(m_bufferFormat))
931                           .c_str());
932         }
933     }
934 
935     // Create buffer to read data from
936     {
937         VkBufferUsageFlags inBufferUsageFlags;
938         VkMemoryRequirements inBufferMemoryReqs;
939 
940         if (isTexelAccess)
941         {
942             inBufferUsageFlags =
943                 readFromStorage ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
944         }
945         else
946         {
947             inBufferUsageFlags =
948                 readFromStorage ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
949         }
950 
951         const VkBufferCreateInfo inBufferParams = {
952             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
953             DE_NULL,                              // const void* pNext;
954             0u,                                   // VkBufferCreateFlags flags;
955             m_inBufferAccessRange,                // VkDeviceSize size;
956             inBufferUsageFlags,                   // VkBufferUsageFlags usage;
957             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
958             VK_QUEUE_FAMILY_IGNORED,              // uint32_t queueFamilyIndexCount;
959             DE_NULL                               // const uint32_t* pQueueFamilyIndices;
960         };
961 
962         m_inBuffer = createBuffer(vk, *m_device, &inBufferParams);
963 
964         inBufferMemoryReqs  = getBufferMemoryRequirements(vk, *m_device, *m_inBuffer);
965         m_inBufferAllocSize = inBufferMemoryReqs.size;
966         m_inBufferAlloc     = memAlloc.allocate(inBufferMemoryReqs, MemoryRequirement::HostVisible);
967 
968         // Size of the most restrictive bound
969         m_inBufferMaxAccessRange = min(m_inBufferAllocSize, min(inBufferParams.size, m_inBufferAccessRange));
970 
971         VK_CHECK(
972             vk.bindBufferMemory(*m_device, *m_inBuffer, m_inBufferAlloc->getMemory(), m_inBufferAlloc->getOffset()));
973         populateBufferWithTestValues(m_inBufferAlloc->getHostPtr(), m_inBufferAllocSize, m_bufferFormat);
974         flushMappedMemoryRange(vk, *m_device, m_inBufferAlloc->getMemory(), m_inBufferAlloc->getOffset(),
975                                VK_WHOLE_SIZE);
976 
977         log << tcu::TestLog::Message << "inBufferAllocSize = " << m_inBufferAllocSize << tcu::TestLog::EndMessage;
978         log << tcu::TestLog::Message << "inBufferMaxAccessRange = " << m_inBufferMaxAccessRange
979             << tcu::TestLog::EndMessage;
980     }
981 
982     // Create buffer to write data into
983     {
984         VkMemoryRequirements outBufferMemoryReqs;
985         const VkBufferUsageFlags outBufferUsageFlags = (m_shaderType == SHADER_TYPE_TEXEL_COPY) ?
986                                                            VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT :
987                                                            VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
988 
989         const VkBufferCreateInfo outBufferParams = {
990             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
991             DE_NULL,                              // const void* pNext;
992             0u,                                   // VkBufferCreateFlags flags;
993             m_outBufferAccessRange,               // VkDeviceSize size;
994             outBufferUsageFlags,                  // VkBufferUsageFlags usage;
995             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
996             VK_QUEUE_FAMILY_IGNORED,              // uint32_t queueFamilyIndexCount;
997             DE_NULL                               // const uint32_t* pQueueFamilyIndices;
998         };
999 
1000         m_outBuffer = createBuffer(vk, *m_device, &outBufferParams);
1001 
1002         outBufferMemoryReqs  = getBufferMemoryRequirements(vk, *m_device, *m_outBuffer);
1003         m_outBufferAllocSize = outBufferMemoryReqs.size;
1004         m_outBufferAlloc     = memAlloc.allocate(outBufferMemoryReqs, MemoryRequirement::HostVisible);
1005 
1006 #ifdef CTS_USES_VULKANSC
1007         if (m_context.getTestContext().getCommandLine().isSubProcess())
1008 #endif // CTS_USES_VULKANSC
1009         {
1010             // If we are requesting access out of the memory that backs the buffer, make sure the test is able to do so.
1011             if (m_accessOutOfBackingMemory)
1012             {
1013                 if (m_outBufferAllocSize >= ((RobustBufferAccessTest::s_testArraySize + 1) * numberOfBytesAccessed))
1014                 {
1015                     TCU_THROW(NotSupportedError, "Cannot access beyond the end of the memory that backs the buffer");
1016                 }
1017             }
1018         }
1019 
1020         // Size of the most restrictive bound
1021         m_outBufferMaxAccessRange = min(m_outBufferAllocSize, min(outBufferParams.size, m_outBufferAccessRange));
1022 
1023         VK_CHECK(
1024             vk.bindBufferMemory(*m_device, *m_outBuffer, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset()));
1025         deMemset(m_outBufferAlloc->getHostPtr(), 0xFF, (size_t)m_outBufferAllocSize);
1026         flushMappedMemoryRange(vk, *m_device, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset(),
1027                                VK_WHOLE_SIZE);
1028 
1029         log << tcu::TestLog::Message << "outBufferAllocSize = " << m_outBufferAllocSize << tcu::TestLog::EndMessage;
1030         log << tcu::TestLog::Message << "outBufferMaxAccessRange = " << m_outBufferMaxAccessRange
1031             << tcu::TestLog::EndMessage;
1032     }
1033 
1034     // Create buffer for indices/offsets
1035     {
1036         struct IndicesBuffer
1037         {
1038             int32_t inIndex;
1039             int32_t outIndex;
1040         };
1041 
1042         IndicesBuffer indices = {0, 0};
1043 
1044         const VkBufferCreateInfo indicesBufferParams = {
1045             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1046             DE_NULL,                              // const void* pNext;
1047             0u,                                   // VkBufferCreateFlags flags;
1048             sizeof(IndicesBuffer),                // VkDeviceSize size;
1049             VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,   // VkBufferUsageFlags usage;
1050             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
1051             VK_QUEUE_FAMILY_IGNORED,              // uint32_t queueFamilyIndexCount;
1052             DE_NULL,                              // const uint32_t* pQueueFamilyIndices;
1053         };
1054 
1055         m_indicesBuffer      = createBuffer(vk, *m_device, &indicesBufferParams);
1056         m_indicesBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_indicesBuffer),
1057                                                  MemoryRequirement::HostVisible);
1058 
1059         VK_CHECK(vk.bindBufferMemory(*m_device, *m_indicesBuffer, m_indicesBufferAlloc->getMemory(),
1060                                      m_indicesBufferAlloc->getOffset()));
1061 
1062         if (m_accessOutOfBackingMemory)
1063         {
1064             if (m_shaderType == SHADER_TYPE_VECTOR_MEMBER_COPY)
1065             {
1066                 if (m_bufferAccessType == BUFFER_ACCESS_TYPE_WRITE)
1067                 {
1068                     indices.outIndex = RobustBufferAccessTest::s_testVectorSize - 1;
1069                 }
1070                 else
1071                 {
1072                     indices.inIndex = RobustBufferAccessTest::s_testVectorSize - 1;
1073                 }
1074             }
1075             else
1076             {
1077                 if (m_bufferAccessType == BUFFER_ACCESS_TYPE_WRITE)
1078                 {
1079                     indices.outIndex = RobustBufferAccessTest::s_testArraySize - 1;
1080                 }
1081                 else
1082                 {
1083                     indices.inIndex = RobustBufferAccessTest::s_testArraySize - 1;
1084                 }
1085             }
1086         }
1087 
1088         deMemcpy(m_indicesBufferAlloc->getHostPtr(), &indices, sizeof(IndicesBuffer));
1089 
1090         flushMappedMemoryRange(vk, *m_device, m_indicesBufferAlloc->getMemory(), m_indicesBufferAlloc->getOffset(),
1091                                VK_WHOLE_SIZE);
1092 
1093         log << tcu::TestLog::Message << "inIndex = " << indices.inIndex << tcu::TestLog::EndMessage;
1094         log << tcu::TestLog::Message << "outIndex = " << indices.outIndex << tcu::TestLog::EndMessage;
1095     }
1096 
1097     // Create descriptor data
1098     {
1099         VkDescriptorType inBufferDescriptorType;
1100         VkDescriptorType outBufferDescriptorType;
1101 
1102         if (isTexelAccess)
1103         {
1104             inBufferDescriptorType =
1105                 readFromStorage ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
1106             outBufferDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
1107         }
1108         else
1109         {
1110             inBufferDescriptorType =
1111                 readFromStorage ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1112             outBufferDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1113         }
1114 
1115         DescriptorPoolBuilder descriptorPoolBuilder;
1116         descriptorPoolBuilder.addType(inBufferDescriptorType, 1u);
1117         descriptorPoolBuilder.addType(outBufferDescriptorType, 1u);
1118         descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u);
1119         m_descriptorPool =
1120             descriptorPoolBuilder.build(vk, *m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1121 
1122         DescriptorSetLayoutBuilder setLayoutBuilder;
1123         setLayoutBuilder.addSingleBinding(inBufferDescriptorType, VK_SHADER_STAGE_ALL);
1124         setLayoutBuilder.addSingleBinding(outBufferDescriptorType, VK_SHADER_STAGE_ALL);
1125         setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
1126         m_descriptorSetLayout = setLayoutBuilder.build(vk, *m_device);
1127 
1128         const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
1129             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
1130             DE_NULL,                                        // const void* pNext;
1131             *m_descriptorPool,                              // VkDescriptorPool descriptorPool;
1132             1u,                                             // uint32_t setLayoutCount;
1133             &m_descriptorSetLayout.get()                    // const VkDescriptorSetLayout* pSetLayouts;
1134         };
1135 
1136         m_descriptorSet = allocateDescriptorSet(vk, *m_device, &descriptorSetAllocateInfo);
1137 
1138         DescriptorSetUpdateBuilder setUpdateBuilder;
1139 
1140         if (isTexelAccess)
1141         {
1142             const VkBufferViewCreateInfo inBufferViewCreateInfo = {
1143                 VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType;
1144                 DE_NULL,                                   // const void* pNext;
1145                 0u,                                        // VkBufferViewCreateFlags flags;
1146                 *m_inBuffer,                               // VkBuffer buffer;
1147                 m_bufferFormat,                            // VkFormat format;
1148                 0ull,                                      // VkDeviceSize offset;
1149                 m_inBufferAccessRange                      // VkDeviceSize range;
1150             };
1151             m_inTexelBufferView = createBufferView(vk, *m_device, &inBufferViewCreateInfo, DE_NULL);
1152 
1153             const VkBufferViewCreateInfo outBufferViewCreateInfo = {
1154                 VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType sType;
1155                 DE_NULL,                                   // const void* pNext;
1156                 0u,                                        // VkBufferViewCreateFlags flags;
1157                 *m_outBuffer,                              // VkBuffer buffer;
1158                 m_bufferFormat,                            // VkFormat format;
1159                 0ull,                                      // VkDeviceSize offset;
1160                 m_outBufferAccessRange,                    // VkDeviceSize range;
1161             };
1162             m_outTexelBufferView = createBufferView(vk, *m_device, &outBufferViewCreateInfo, DE_NULL);
1163 
1164             setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0),
1165                                          inBufferDescriptorType, &m_inTexelBufferView.get());
1166             setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1),
1167                                          outBufferDescriptorType, &m_outTexelBufferView.get());
1168         }
1169         else
1170         {
1171             const VkDescriptorBufferInfo inBufferDescriptorInfo =
1172                 makeDescriptorBufferInfo(*m_inBuffer, 0ull, m_inBufferAccessRange);
1173             const VkDescriptorBufferInfo outBufferDescriptorInfo =
1174                 makeDescriptorBufferInfo(*m_outBuffer, 0ull, m_outBufferAccessRange);
1175 
1176             setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0),
1177                                          inBufferDescriptorType, &inBufferDescriptorInfo);
1178             setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1),
1179                                          outBufferDescriptorType, &outBufferDescriptorInfo);
1180         }
1181 
1182         const VkDescriptorBufferInfo indicesBufferDescriptorInfo =
1183             makeDescriptorBufferInfo(*m_indicesBuffer, 0ull, 8ull);
1184         setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2),
1185                                      VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &indicesBufferDescriptorInfo);
1186 
1187         setUpdateBuilder.update(vk, *m_device);
1188     }
1189 
1190     // Create fence
1191     {
1192         const VkFenceCreateInfo fenceParams = {
1193             VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
1194             DE_NULL,                             // const void* pNext;
1195             0u                                   // VkFenceCreateFlags flags;
1196         };
1197 
1198         m_fence = createFence(vk, *m_device, &fenceParams);
1199     }
1200 
1201     // Get queue
1202     vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &m_queue);
1203 
1204     if (m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
1205     {
1206         m_testEnvironment = de::MovePtr<TestEnvironment>(new ComputeEnvironment(
1207             m_context, *m_deviceDriver, *m_device, *m_descriptorSetLayout, *m_descriptorSet, m_testPipelineRobustness));
1208     }
1209     else
1210     {
1211         using tcu::Vec4;
1212 
1213         const VkVertexInputBindingDescription vertexInputBindingDescription = {
1214             0u,                         // uint32_t binding;
1215             sizeof(tcu::Vec4),          // uint32_t strideInBytes;
1216             VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
1217         };
1218 
1219         const VkVertexInputAttributeDescription vertexInputAttributeDescription = {
1220             0u,                            // uint32_t location;
1221             0u,                            // uint32_t binding;
1222             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
1223             0u                             // uint32_t offset;
1224         };
1225 
1226         const Vec4 vertices[] = {
1227             Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1228             Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1229             Vec4(1.0f, -1.0f, 0.0f, 1.0f),
1230         };
1231 
1232         // Create vertex buffer
1233         {
1234             const VkDeviceSize vertexBufferSize         = (VkDeviceSize)(4u * sizeof(tcu::Vec4));
1235             const VkBufferCreateInfo vertexBufferParams = {
1236                 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1237                 DE_NULL,                              // const void* pNext;
1238                 0u,                                   // VkBufferCreateFlags flags;
1239                 vertexBufferSize,                     // VkDeviceSize size;
1240                 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
1241                 VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
1242                 VK_QUEUE_FAMILY_IGNORED,              // uint32_t queueFamilyIndexCount;
1243                 DE_NULL                               // const uint32_t* pQueueFamilyIndices;
1244             };
1245 
1246             DE_ASSERT(vertexBufferSize > 0);
1247 
1248             m_vertexBuffer      = createBuffer(vk, *m_device, &vertexBufferParams);
1249             m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_vertexBuffer),
1250                                                     MemoryRequirement::HostVisible);
1251 
1252             VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(),
1253                                          m_vertexBufferAlloc->getOffset()));
1254 
1255             // Load vertices into vertex buffer
1256             deMemcpy(m_vertexBufferAlloc->getHostPtr(), vertices, sizeof(tcu::Vec4) * DE_LENGTH_OF_ARRAY(vertices));
1257             flushMappedMemoryRange(vk, *m_device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(),
1258                                    VK_WHOLE_SIZE);
1259         }
1260 
1261         const GraphicsEnvironment::DrawConfig drawWithOneVertexBuffer = {
1262             std::vector<VkBuffer>(1, *m_vertexBuffer), // std::vector<VkBuffer> vertexBuffers;
1263             DE_LENGTH_OF_ARRAY(vertices),              // uint32_t vertexCount;
1264             1,                                         // uint32_t instanceCount;
1265             DE_NULL,                                   // VkBuffer indexBuffer;
1266             0u,                                        // uint32_t indexCount;
1267         };
1268 
1269         m_testEnvironment = de::MovePtr<TestEnvironment>(
1270             new GraphicsEnvironment(m_context, *m_deviceDriver, *m_device, *m_descriptorSetLayout, *m_descriptorSet,
1271                                     GraphicsEnvironment::VertexBindings(1, vertexInputBindingDescription),
1272                                     GraphicsEnvironment::VertexAttributes(1, vertexInputAttributeDescription),
1273                                     drawWithOneVertexBuffer, m_testPipelineRobustness));
1274     }
1275 }
1276 
~BufferAccessInstance(void)1277 BufferAccessInstance::~BufferAccessInstance(void)
1278 {
1279 }
1280 
1281 // Verifies if the buffer has the value initialized by BufferAccessInstance::populateReadBuffer at a given offset.
isExpectedValueFromInBuffer(VkDeviceSize offsetInBytes,const void * valuePtr,VkDeviceSize valueSize)1282 bool BufferAccessInstance::isExpectedValueFromInBuffer(VkDeviceSize offsetInBytes, const void *valuePtr,
1283                                                        VkDeviceSize valueSize)
1284 {
1285     DE_ASSERT(offsetInBytes % 4 == 0);
1286     DE_ASSERT(offsetInBytes < m_inBufferAllocSize);
1287 
1288     const uint32_t valueIndex = uint32_t(offsetInBytes / 4) + 2;
1289 
1290     if (isUintFormat(m_bufferFormat))
1291     {
1292         return !deMemCmp(valuePtr, &valueIndex, (size_t)valueSize);
1293     }
1294     else if (isIntFormat(m_bufferFormat))
1295     {
1296         const int32_t value = -int32_t(valueIndex);
1297         return !deMemCmp(valuePtr, &value, (size_t)valueSize);
1298     }
1299     else if (isFloatFormat(m_bufferFormat))
1300     {
1301         const float value = float(valueIndex);
1302         return !deMemCmp(valuePtr, &value, (size_t)valueSize);
1303     }
1304     else if (m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1305     {
1306         const uint32_t r    = ((valueIndex + 0) & ((2u << 10) - 1u));
1307         const uint32_t g    = ((valueIndex + 1) & ((2u << 10) - 1u));
1308         const uint32_t b    = ((valueIndex + 2) & ((2u << 10) - 1u));
1309         const uint32_t a    = ((valueIndex + 0) & ((2u << 2) - 1u));
1310         const uint32_t abgr = (a << 30) | (b << 20) | (g << 10) | r;
1311 
1312         return !deMemCmp(valuePtr, &abgr, (size_t)valueSize);
1313     }
1314     else
1315     {
1316         DE_ASSERT(false);
1317         return false;
1318     }
1319 }
1320 
isOutBufferValueUnchanged(VkDeviceSize offsetInBytes,VkDeviceSize valueSize)1321 bool BufferAccessInstance::isOutBufferValueUnchanged(VkDeviceSize offsetInBytes, VkDeviceSize valueSize)
1322 {
1323     const uint8_t *const outValuePtr = (uint8_t *)m_outBufferAlloc->getHostPtr() + offsetInBytes;
1324     const uint32_t defaultValue      = 0xFFFFFFFFu;
1325 
1326     return !deMemCmp(outValuePtr, &defaultValue, (size_t)valueSize);
1327 }
1328 
iterate(void)1329 tcu::TestStatus BufferAccessInstance::iterate(void)
1330 {
1331     const DeviceInterface &vk           = *m_deviceDriver;
1332     const vk::VkCommandBuffer cmdBuffer = m_testEnvironment->getCommandBuffer();
1333 
1334     // Submit command buffer
1335     {
1336         const VkSubmitInfo submitInfo = {
1337             VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
1338             DE_NULL,                       // const void* pNext;
1339             0u,                            // uint32_t waitSemaphoreCount;
1340             DE_NULL,                       // const VkSemaphore* pWaitSemaphores;
1341             DE_NULL,                       // const VkPIpelineStageFlags* pWaitDstStageMask;
1342             1u,                            // uint32_t commandBufferCount;
1343             &cmdBuffer,                    // const VkCommandBuffer* pCommandBuffers;
1344             0u,                            // uint32_t signalSemaphoreCount;
1345             DE_NULL                        // const VkSemaphore* pSignalSemaphores;
1346         };
1347 
1348         VK_CHECK(vk.resetFences(*m_device, 1, &m_fence.get()));
1349         VK_CHECK(vk.queueSubmit(m_queue, 1, &submitInfo, *m_fence));
1350         VK_CHECK(vk.waitForFences(*m_device, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
1351     }
1352 
1353     // Prepare result buffer for read
1354     {
1355         const VkMappedMemoryRange outBufferRange = {
1356             VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, //  VkStructureType sType;
1357             DE_NULL,                               //  const void* pNext;
1358             m_outBufferAlloc->getMemory(),         //  VkDeviceMemory mem;
1359             0ull,                                  //  VkDeviceSize offset;
1360             m_outBufferAllocSize,                  //  VkDeviceSize size;
1361         };
1362 
1363         VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
1364     }
1365 
1366     if (verifyResult())
1367         return tcu::TestStatus::pass("All values OK");
1368     else
1369         return tcu::TestStatus::fail("Invalid value(s) found");
1370 }
1371 
verifyResult(void)1372 bool BufferAccessInstance::verifyResult(void)
1373 {
1374     std::ostringstream logMsg;
1375     tcu::TestLog &log = m_context.getTestContext().getLog();
1376     const bool isReadAccess =
1377         !!(m_bufferAccessType == BUFFER_ACCESS_TYPE_READ || m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE);
1378     const void *inDataPtr             = m_inBufferAlloc->getHostPtr();
1379     const void *outDataPtr            = m_outBufferAlloc->getHostPtr();
1380     bool allOk                        = true;
1381     uint32_t valueNdx                 = 0;
1382     const VkDeviceSize maxAccessRange = isReadAccess ? m_inBufferMaxAccessRange : m_outBufferMaxAccessRange;
1383 
1384     for (VkDeviceSize offsetInBytes = 0; offsetInBytes < m_outBufferAllocSize; offsetInBytes += 4)
1385     {
1386         uint8_t *outValuePtr      = (uint8_t *)outDataPtr + offsetInBytes;
1387         const size_t outValueSize = (size_t)min(4, (m_outBufferAllocSize - offsetInBytes));
1388 
1389         if (offsetInBytes >= RobustBufferAccessTest::getNumberOfBytesAccesssed(m_shaderType))
1390         {
1391             // The shader will only write 16 values into the result buffer. The rest of the values
1392             // should remain unchanged or may be modified if we are writing out of bounds.
1393             if (!isOutBufferValueUnchanged(offsetInBytes, outValueSize) &&
1394                 (isReadAccess || !isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, 4)))
1395             {
1396                 logMsg << "\nValue " << valueNdx++
1397                        << " has been modified with an unknown value: " << *((uint32_t *)outValuePtr);
1398                 allOk = false;
1399             }
1400         }
1401         else
1402         {
1403             const int32_t distanceToOutOfBounds = (int32_t)maxAccessRange - (int32_t)offsetInBytes;
1404             bool isOutOfBoundsAccess            = false;
1405 
1406             logMsg << "\n" << valueNdx++ << ": ";
1407 
1408             logValue(logMsg, outValuePtr, m_bufferFormat, outValueSize);
1409 
1410             if (m_accessOutOfBackingMemory)
1411             {
1412                 isOutOfBoundsAccess = true;
1413             }
1414             else
1415             {
1416                 // Check if the shader operation accessed an operand located less than 16 bytes away
1417                 // from the out of bounds address.
1418 
1419                 uint32_t operandSize = 0;
1420 
1421                 switch (m_shaderType)
1422                 {
1423                 case SHADER_TYPE_SCALAR_COPY:
1424                     operandSize = 4; // Size of scalar
1425                     break;
1426 
1427                 case SHADER_TYPE_VECTOR_COPY:
1428                     operandSize =
1429                         4 * ((m_bufferFormat == vk::VK_FORMAT_R64_UINT || m_bufferFormat == vk::VK_FORMAT_R64_SINT) ?
1430                                  8 :
1431                                  4); // Size of vec4
1432                     break;
1433 
1434                 case SHADER_TYPE_VECTOR_MEMBER_COPY:
1435                     operandSize =
1436                         ((m_bufferFormat == vk::VK_FORMAT_R64_UINT || m_bufferFormat == vk::VK_FORMAT_R64_SINT) ?
1437                              8 :
1438                              4); // Size of vec4
1439                     break;
1440 
1441                 case SHADER_TYPE_MATRIX_COPY:
1442                     operandSize = 4 * 16; // Size of mat4
1443                     break;
1444 
1445                 case SHADER_TYPE_TEXEL_COPY:
1446                     operandSize = mapVkFormat(m_bufferFormat).getPixelSize();
1447                     break;
1448 
1449                 default:
1450                     DE_ASSERT(false);
1451                 }
1452 
1453                 isOutOfBoundsAccess = (maxAccessRange < 16) ||
1454                                       (((offsetInBytes / operandSize + 1) * operandSize) > (maxAccessRange - 16));
1455             }
1456 
1457             if (isOutOfBoundsAccess)
1458             {
1459                 logMsg << " (out of bounds " << (isReadAccess ? "read" : "write") << ")";
1460 
1461                 const bool isValuePartiallyOutOfBounds =
1462                     ((distanceToOutOfBounds > 0) && ((uint32_t)distanceToOutOfBounds < 4));
1463                 bool isValidValue = false;
1464 
1465                 if (isValuePartiallyOutOfBounds && !m_accessOutOfBackingMemory)
1466                 {
1467                     // The value is partially out of bounds
1468 
1469                     bool isOutOfBoundsPartOk  = true;
1470                     bool isWithinBoundsPartOk = true;
1471 
1472                     if (isReadAccess)
1473                     {
1474                         isWithinBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr,
1475                                                                          distanceToOutOfBounds);
1476                         isOutOfBoundsPartOk  = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize,
1477                                                                          (uint8_t *)outValuePtr + distanceToOutOfBounds,
1478                                                                          outValueSize - distanceToOutOfBounds);
1479                     }
1480                     else
1481                     {
1482                         isWithinBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr,
1483                                                                          distanceToOutOfBounds) ||
1484                                                isOutBufferValueUnchanged(offsetInBytes, distanceToOutOfBounds);
1485 
1486                         isOutOfBoundsPartOk = isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize,
1487                                                                         (uint8_t *)outValuePtr + distanceToOutOfBounds,
1488                                                                         outValueSize - distanceToOutOfBounds) ||
1489                                               isOutBufferValueUnchanged(offsetInBytes + distanceToOutOfBounds,
1490                                                                         outValueSize - distanceToOutOfBounds);
1491                     }
1492 
1493                     logMsg << ", first " << distanceToOutOfBounds << " byte(s) "
1494                            << (isWithinBoundsPartOk ? "OK" : "wrong");
1495                     logMsg << ", last " << outValueSize - distanceToOutOfBounds << " byte(s) "
1496                            << (isOutOfBoundsPartOk ? "OK" : "wrong");
1497 
1498                     isValidValue = isWithinBoundsPartOk && isOutOfBoundsPartOk;
1499                 }
1500                 else
1501                 {
1502                     if (isReadAccess)
1503                     {
1504                         isValidValue =
1505                             isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, outValueSize);
1506                     }
1507                     else
1508                     {
1509                         isValidValue = isOutBufferValueUnchanged(offsetInBytes, outValueSize);
1510 
1511                         if (!isValidValue)
1512                         {
1513                             // Out of bounds writes may modify values withing the memory ranges bound to the buffer
1514                             isValidValue =
1515                                 isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, outValueSize);
1516 
1517                             if (isValidValue)
1518                                 logMsg << ", OK, written within the memory range bound to the buffer";
1519                         }
1520                     }
1521                 }
1522 
1523                 if (!isValidValue)
1524                 {
1525                     // Check if we are satisfying the [0, 0, 0, x] pattern, where x may be either 0 or 1,
1526                     // or the maximum representable positive integer value (if the format is integer-based).
1527 
1528                     const bool canMatchVec4Pattern =
1529                         (isReadAccess && !isValuePartiallyOutOfBounds &&
1530                          (m_shaderType == SHADER_TYPE_VECTOR_COPY || m_shaderType == SHADER_TYPE_VECTOR_MEMBER_COPY ||
1531                           m_shaderType == SHADER_TYPE_TEXEL_COPY) &&
1532                          ((offsetInBytes / 4 + 1) % 4 == 0 || m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32));
1533                     bool matchesVec4Pattern = false;
1534 
1535                     if (canMatchVec4Pattern)
1536                     {
1537                         if (m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1538                             matchesVec4Pattern = verifyOutOfBoundsVec4(outValuePtr, m_bufferFormat);
1539                         else
1540                             matchesVec4Pattern =
1541                                 verifyOutOfBoundsVec4(reinterpret_cast<uint32_t *>(outValuePtr) - 3, m_bufferFormat);
1542                     }
1543 
1544                     if (!canMatchVec4Pattern || !matchesVec4Pattern)
1545                     {
1546                         logMsg << ". Failed: ";
1547 
1548                         if (isReadAccess)
1549                         {
1550                             logMsg << "expected value within the buffer range or 0";
1551 
1552                             if (canMatchVec4Pattern)
1553                                 logMsg << ", or the [0, 0, 0, x] pattern";
1554                         }
1555                         else
1556                         {
1557                             logMsg << "written out of the range";
1558                         }
1559 
1560                         allOk = false;
1561                     }
1562                 }
1563             }
1564             else // We are within bounds
1565             {
1566                 if (isReadAccess)
1567                 {
1568                     if (!isExpectedValueFromInBuffer(offsetInBytes, outValuePtr, 4))
1569                     {
1570                         logMsg << ", Failed: unexpected value";
1571                         allOk = false;
1572                     }
1573                 }
1574                 else
1575                 {
1576                     // Out of bounds writes may change values within the bounds.
1577                     if (!isValueWithinBufferOrZero(inDataPtr, m_inBufferAccessRange, outValuePtr, 4))
1578                     {
1579                         logMsg << ", Failed: unexpected value";
1580                         allOk = false;
1581                     }
1582                 }
1583             }
1584         }
1585     }
1586 
1587     log << tcu::TestLog::Message << logMsg.str() << tcu::TestLog::EndMessage;
1588 
1589     return allOk;
1590 }
1591 
1592 // BufferReadInstance
1593 
BufferReadInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,ShaderType shaderType,VkShaderStageFlags shaderStage,VkFormat bufferFormat,bool readFromStorage,VkDeviceSize inBufferAccessRange,bool accessOutOfBackingMemory,bool testPipelineRobustness)1594 BufferReadInstance::BufferReadInstance(Context &context, Move<VkDevice> device,
1595 #ifndef CTS_USES_VULKANSC
1596                                        de::MovePtr<vk::DeviceDriver> deviceDriver,
1597 #else
1598                                        de::MovePtr<CustomInstance> customInstance,
1599                                        de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
1600 #endif // CTS_USES_VULKANSC
1601                                        ShaderType shaderType, VkShaderStageFlags shaderStage, VkFormat bufferFormat,
1602                                        bool readFromStorage, VkDeviceSize inBufferAccessRange,
1603                                        bool accessOutOfBackingMemory, bool testPipelineRobustness)
1604 
1605     : BufferAccessInstance(context, device,
1606 #ifdef CTS_USES_VULKANSC
1607                            customInstance,
1608 #endif // CTS_USES_VULKANSC
1609                            deviceDriver, shaderType, shaderStage, bufferFormat,
1610                            readFromStorage ? BUFFER_ACCESS_TYPE_READ_FROM_STORAGE : BUFFER_ACCESS_TYPE_READ,
1611                            inBufferAccessRange,
1612                            RobustBufferAccessTest::getNumberOfBytesAccesssed(shaderType), // outBufferAccessRange
1613                            accessOutOfBackingMemory, testPipelineRobustness)
1614 {
1615 }
1616 
1617 // BufferWriteInstance
1618 
BufferWriteInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,ShaderType shaderType,VkShaderStageFlags shaderStage,VkFormat bufferFormat,VkDeviceSize writeBufferAccessRange,bool accessOutOfBackingMemory,bool testPipelineRobustness)1619 BufferWriteInstance::BufferWriteInstance(Context &context, Move<VkDevice> device,
1620 #ifndef CTS_USES_VULKANSC
1621                                          de::MovePtr<vk::DeviceDriver> deviceDriver,
1622 #else
1623                                          de::MovePtr<CustomInstance> customInstance,
1624                                          de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
1625 #endif // CTS_USES_VULKANSC
1626                                          ShaderType shaderType, VkShaderStageFlags shaderStage, VkFormat bufferFormat,
1627                                          VkDeviceSize writeBufferAccessRange, bool accessOutOfBackingMemory,
1628                                          bool testPipelineRobustness)
1629 
1630     : BufferAccessInstance(context, device,
1631 #ifdef CTS_USES_VULKANSC
1632                            customInstance,
1633 #endif // CTS_USES_VULKANSC
1634                            deviceDriver, shaderType, shaderStage, bufferFormat, BUFFER_ACCESS_TYPE_WRITE,
1635                            RobustBufferAccessTest::getNumberOfBytesAccesssed(shaderType), // inBufferAccessRange
1636                            writeBufferAccessRange, accessOutOfBackingMemory, testPipelineRobustness)
1637 {
1638 }
1639 
1640 // Test node creation functions
1641 
getShaderStageName(VkShaderStageFlagBits shaderStage)1642 static const char *getShaderStageName(VkShaderStageFlagBits shaderStage)
1643 {
1644     switch (shaderStage)
1645     {
1646     case VK_SHADER_STAGE_VERTEX_BIT:
1647         return "vertex";
1648     case VK_SHADER_STAGE_FRAGMENT_BIT:
1649         return "fragment";
1650     case VK_SHADER_STAGE_COMPUTE_BIT:
1651         return "compute";
1652     case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
1653         return "tess_control";
1654     case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
1655         return "tess_eval";
1656     case VK_SHADER_STAGE_GEOMETRY_BIT:
1657         return "geometry";
1658 
1659     default:
1660         DE_ASSERT(false);
1661     }
1662 
1663     return DE_NULL;
1664 }
1665 
addBufferAccessTests(tcu::TestContext & testCtx,tcu::TestCaseGroup * parentNode,bool testPipelineRobustness)1666 static void addBufferAccessTests(tcu::TestContext &testCtx, tcu::TestCaseGroup *parentNode, bool testPipelineRobustness)
1667 {
1668     struct BufferRangeConfig
1669     {
1670         const char *name;
1671         VkDeviceSize range;
1672     };
1673 
1674     const VkShaderStageFlagBits bufferAccessStages[] = {
1675         VK_SHADER_STAGE_VERTEX_BIT,
1676         VK_SHADER_STAGE_FRAGMENT_BIT,
1677         VK_SHADER_STAGE_COMPUTE_BIT,
1678     };
1679 
1680     const VkFormat bufferFormats[] = {VK_FORMAT_R32_SINT, VK_FORMAT_R32_UINT, VK_FORMAT_R64_SINT, VK_FORMAT_R64_UINT,
1681                                       VK_FORMAT_R32_SFLOAT};
1682 
1683     const VkFormat texelBufferFormats[] = {VK_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R32G32B32A32_UINT,
1684                                            VK_FORMAT_R32G32B32A32_SFLOAT,
1685 
1686                                            VK_FORMAT_A2B10G10R10_UNORM_PACK32};
1687 
1688     const BufferRangeConfig bufferRangeConfigs[] = {
1689         {"range_1_byte", 1ull},
1690         {"range_3_bytes", 3ull},
1691         {"range_4_bytes", 4ull},   // size of float
1692         {"range_32_bytes", 32ull}, // size of half mat4
1693     };
1694 
1695     const BufferRangeConfig texelBufferRangeConfigs[] = {
1696         {"range_1_texel", 1u},
1697         {"range_3_texels", 3u},
1698     };
1699 
1700     const char *shaderTypeNames[SHADER_TYPE_COUNT] = {
1701         "mat4_copy", "vec4_copy", "vec4_member_copy", "scalar_copy", "texel_copy",
1702     };
1703 
1704     for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(bufferAccessStages); stageNdx++)
1705     {
1706         const VkShaderStageFlagBits stage = bufferAccessStages[stageNdx];
1707         de::MovePtr<tcu::TestCaseGroup> stageTests(new tcu::TestCaseGroup(testCtx, getShaderStageName(stage)));
1708 
1709         for (int shaderTypeNdx = 0; shaderTypeNdx < SHADER_TYPE_COUNT; shaderTypeNdx++)
1710         {
1711             const VkFormat *formats;
1712             size_t formatsLength;
1713             const BufferRangeConfig *ranges;
1714             size_t rangesLength;
1715             uint32_t rangeMultiplier;
1716             de::MovePtr<tcu::TestCaseGroup> shaderTypeTests(
1717                 new tcu::TestCaseGroup(testCtx, shaderTypeNames[shaderTypeNdx]));
1718 
1719             if ((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY)
1720             {
1721                 formats       = texelBufferFormats;
1722                 formatsLength = DE_LENGTH_OF_ARRAY(texelBufferFormats);
1723 
1724                 ranges       = texelBufferRangeConfigs;
1725                 rangesLength = DE_LENGTH_OF_ARRAY(texelBufferRangeConfigs);
1726             }
1727             else
1728             {
1729                 formats       = bufferFormats;
1730                 formatsLength = DE_LENGTH_OF_ARRAY(bufferFormats);
1731 
1732                 ranges       = bufferRangeConfigs;
1733                 rangesLength = DE_LENGTH_OF_ARRAY(bufferRangeConfigs);
1734             }
1735 
1736             for (size_t formatNdx = 0; formatNdx < formatsLength; formatNdx++)
1737             {
1738                 const VkFormat bufferFormat = formats[formatNdx];
1739 
1740                 rangeMultiplier = ((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY) ?
1741                                       mapVkFormat(bufferFormat).getPixelSize() :
1742                                       1;
1743 
1744                 if (!isFloatFormat(bufferFormat) && ((ShaderType)shaderTypeNdx) == SHADER_TYPE_MATRIX_COPY)
1745                 {
1746                     // Use SHADER_TYPE_MATRIX_COPY with floating-point formats only
1747                     break;
1748                 }
1749 
1750                 // Avoid too much duplication by excluding certain test cases
1751                 if (testPipelineRobustness &&
1752                     !(bufferFormat == VK_FORMAT_R32_UINT || bufferFormat == VK_FORMAT_R64_SINT ||
1753                       bufferFormat == VK_FORMAT_R32_SFLOAT || bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32))
1754                 {
1755                     continue;
1756                 }
1757 
1758                 const std::string formatName = getFormatName(bufferFormat);
1759                 de::MovePtr<tcu::TestCaseGroup> formatTests(
1760                     new tcu::TestCaseGroup(testCtx, de::toLower(formatName.substr(10)).c_str()));
1761 
1762                 de::MovePtr<tcu::TestCaseGroup> uboReadTests(new tcu::TestCaseGroup(testCtx, "oob_uniform_read"));
1763                 de::MovePtr<tcu::TestCaseGroup> ssboReadTests(new tcu::TestCaseGroup(testCtx, "oob_storage_read"));
1764                 de::MovePtr<tcu::TestCaseGroup> ssboWriteTests(new tcu::TestCaseGroup(testCtx, "oob_storage_write"));
1765 
1766                 for (size_t rangeNdx = 0; rangeNdx < rangesLength; rangeNdx++)
1767                 {
1768                     const BufferRangeConfig &rangeConfig = ranges[rangeNdx];
1769                     const VkDeviceSize rangeInBytes      = rangeConfig.range * rangeMultiplier;
1770 
1771                     if (rangeInBytes > 16 && (ShaderType)shaderTypeNdx == SHADER_TYPE_VECTOR_MEMBER_COPY)
1772                     {
1773                         continue;
1774                     }
1775 
1776                     uboReadTests->addChild(
1777                         new RobustBufferReadTest(testCtx, rangeConfig.name, stage, (ShaderType)shaderTypeNdx,
1778                                                  bufferFormat, testPipelineRobustness, rangeInBytes, false, false));
1779 
1780                     // Avoid too much duplication by excluding certain test cases
1781                     if (!testPipelineRobustness)
1782                         ssboReadTests->addChild(
1783                             new RobustBufferReadTest(testCtx, rangeConfig.name, stage, (ShaderType)shaderTypeNdx,
1784                                                      bufferFormat, testPipelineRobustness, rangeInBytes, true, false));
1785 
1786                     ssboWriteTests->addChild(new RobustBufferWriteTest(testCtx, rangeConfig.name, stage,
1787                                                                        (ShaderType)shaderTypeNdx, bufferFormat,
1788                                                                        testPipelineRobustness, rangeInBytes, false));
1789                 }
1790 
1791                 formatTests->addChild(uboReadTests.release());
1792                 formatTests->addChild(ssboReadTests.release());
1793                 formatTests->addChild(ssboWriteTests.release());
1794 
1795                 shaderTypeTests->addChild(formatTests.release());
1796             }
1797 
1798             // Read/write out of the memory that backs the buffer
1799             {
1800                 de::MovePtr<tcu::TestCaseGroup> outOfAllocTests(new tcu::TestCaseGroup(testCtx, "out_of_alloc"));
1801 
1802                 const VkFormat format =
1803                     (((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY) ? VK_FORMAT_R32G32B32A32_SFLOAT :
1804                                                                              VK_FORMAT_R32_SFLOAT);
1805 
1806                 const VkDeviceSize writeAccessRange =
1807                     ((ShaderType)shaderTypeNdx == SHADER_TYPE_VECTOR_MEMBER_COPY) ? 8 : 16;
1808 
1809                 outOfAllocTests->addChild(
1810                     new RobustBufferReadTest(testCtx, "oob_uniform_read", stage, (ShaderType)shaderTypeNdx, format,
1811                                              testPipelineRobustness, writeAccessRange, false, true));
1812 
1813                 // Avoid too much duplication by excluding certain test cases
1814                 if (!testPipelineRobustness)
1815                     outOfAllocTests->addChild(
1816                         new RobustBufferReadTest(testCtx, "oob_storage_read", stage, (ShaderType)shaderTypeNdx, format,
1817                                                  testPipelineRobustness, writeAccessRange, true, true));
1818 
1819                 outOfAllocTests->addChild(new RobustBufferWriteTest(testCtx, "oob_storage_write", stage,
1820                                                                     (ShaderType)shaderTypeNdx, format,
1821                                                                     testPipelineRobustness, writeAccessRange, true));
1822 
1823                 shaderTypeTests->addChild(outOfAllocTests.release());
1824             }
1825 
1826             stageTests->addChild(shaderTypeTests.release());
1827         }
1828         parentNode->addChild(stageTests.release());
1829     }
1830 }
1831 
createBufferAccessTests(tcu::TestContext & testCtx)1832 tcu::TestCaseGroup *createBufferAccessTests(tcu::TestContext &testCtx)
1833 {
1834     de::MovePtr<tcu::TestCaseGroup> bufferAccessTests(new tcu::TestCaseGroup(testCtx, "buffer_access"));
1835 
1836     addBufferAccessTests(testCtx, bufferAccessTests.get(), false);
1837 
1838     return bufferAccessTests.release();
1839 }
1840 
1841 #ifndef CTS_USES_VULKANSC
createPipelineRobustnessBufferAccessTests(tcu::TestContext & testCtx)1842 tcu::TestCaseGroup *createPipelineRobustnessBufferAccessTests(tcu::TestContext &testCtx)
1843 {
1844     de::MovePtr<tcu::TestCaseGroup> bufferAccessTests(
1845         new tcu::TestCaseGroup(testCtx, "pipeline_robustness_buffer_access"));
1846     addBufferAccessTests(testCtx, bufferAccessTests.get(), true);
1847 
1848     return bufferAccessTests.release();
1849 }
1850 #endif
1851 
1852 } // namespace robustness
1853 } // namespace vkt
1854