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