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