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