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 Vertex Buffer Access Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktRobustnessVertexAccessTests.hpp"
26 #include "vktRobustnessUtil.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vkBuilderUtil.hpp"
29 #include "vkImageUtil.hpp"
30 #include "vkMemUtil.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 #include "deMath.h"
39 #include "deUniquePtr.hpp"
40 #include <vector>
41
42 namespace vkt
43 {
44 namespace robustness
45 {
46
47 using namespace vk;
48
49 typedef std::vector<VkVertexInputBindingDescription> BindingList;
50 typedef std::vector<VkVertexInputAttributeDescription> AttributeList;
51
52 class VertexAccessTest : public vkt::TestCase
53 {
54 public:
55 VertexAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
56 uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices, uint32_t numInstances);
57
~VertexAccessTest(void)58 virtual ~VertexAccessTest(void)
59 {
60 }
61
62 void initPrograms(SourceCollections &programCollection) const;
63 void checkSupport(Context &context) const;
64 TestInstance *createInstance(Context &context) const = 0;
65
66 protected:
67 const VkFormat m_inputFormat;
68 const uint32_t m_numVertexValues;
69 const uint32_t m_numInstanceValues;
70 const uint32_t m_numVertices;
71 const uint32_t m_numInstances;
72 };
73
74 class DrawAccessTest : public VertexAccessTest
75 {
76 public:
77 DrawAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
78 uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices, uint32_t numInstances);
79
~DrawAccessTest(void)80 virtual ~DrawAccessTest(void)
81 {
82 }
83 TestInstance *createInstance(Context &context) const;
84
85 protected:
86 };
87
88 class DrawIndexedAccessTest : public VertexAccessTest
89 {
90 public:
91 enum IndexConfig
92 {
93 INDEX_CONFIG_LAST_INDEX_OUT_OF_BOUNDS,
94 INDEX_CONFIG_INDICES_OUT_OF_BOUNDS,
95 INDEX_CONFIG_TRIANGLE_OUT_OF_BOUNDS,
96
97 INDEX_CONFIG_COUNT
98 };
99
100 const static std::vector<uint32_t> s_indexConfigs[INDEX_CONFIG_COUNT];
101
102 DrawIndexedAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
103 IndexConfig indexConfig);
104
~DrawIndexedAccessTest(void)105 virtual ~DrawIndexedAccessTest(void)
106 {
107 }
108 TestInstance *createInstance(Context &context) const;
109
110 protected:
111 const IndexConfig m_indexConfig;
112 };
113
114 class VertexAccessInstance : public vkt::TestInstance
115 {
116 public:
117 VertexAccessInstance(Context &context, Move<VkDevice> device,
118 #ifndef CTS_USES_VULKANSC
119 de::MovePtr<vk::DeviceDriver> deviceDriver,
120 #else
121 de::MovePtr<CustomInstance> customInstance,
122 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
123 #endif // CTS_USES_VULKANSC
124 VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues,
125 uint32_t numVertices, uint32_t numInstances, const std::vector<uint32_t> &indices);
126
127 virtual ~VertexAccessInstance(void);
128 virtual tcu::TestStatus iterate(void);
129 virtual bool verifyResult(void);
130
131 private:
132 bool isValueWithinVertexBufferOrZero(void *vertexBuffer, VkDeviceSize vertexBufferSize, const void *value,
133 uint32_t valueIndexa);
134
135 protected:
136 static bool isExpectedValueFromVertexBuffer(const void *vertexBuffer, uint32_t vertexIndex, VkFormat vertexFormat,
137 const void *value);
138 static VkDeviceSize getBufferSizeInBytes(uint32_t numScalars, VkFormat format);
139
140 virtual void initVertexIds(uint32_t *indicesPtr, size_t indexCount) = 0;
141 virtual uint32_t getIndex(uint32_t vertexNum) const = 0;
142
143 #ifndef CTS_USES_VULKANSC
144 Move<VkDevice> m_device;
145 de::MovePtr<vk::DeviceDriver> m_deviceDriver;
146 #else
147 // Construction needs to happen in this exact order to ensure proper resource destruction
148 de::MovePtr<CustomInstance> m_customInstance;
149 Move<VkDevice> m_device;
150 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> m_deviceDriver;
151 #endif // CTS_USES_VULKANSC
152
153 const VkFormat m_inputFormat;
154 const uint32_t m_numVertexValues;
155 const uint32_t m_numInstanceValues;
156 const uint32_t m_numVertices;
157 const uint32_t m_numInstances;
158 AttributeList m_vertexInputAttributes;
159 BindingList m_vertexInputBindings;
160
161 Move<VkBuffer> m_vertexRateBuffer;
162 VkDeviceSize m_vertexRateBufferSize;
163 de::MovePtr<Allocation> m_vertexRateBufferAlloc;
164 VkDeviceSize m_vertexRateBufferAllocSize;
165
166 Move<VkBuffer> m_instanceRateBuffer;
167 VkDeviceSize m_instanceRateBufferSize;
168 de::MovePtr<Allocation> m_instanceRateBufferAlloc;
169 VkDeviceSize m_instanceRateBufferAllocSize;
170
171 Move<VkBuffer> m_vertexNumBuffer;
172 VkDeviceSize m_vertexNumBufferSize;
173 de::MovePtr<Allocation> m_vertexNumBufferAlloc;
174
175 Move<VkBuffer> m_indexBuffer;
176 VkDeviceSize m_indexBufferSize;
177 de::MovePtr<Allocation> m_indexBufferAlloc;
178
179 Move<VkBuffer> m_outBuffer; // SSBO
180 VkDeviceSize m_outBufferSize;
181 de::MovePtr<Allocation> m_outBufferAlloc;
182 VkDeviceSize m_outBufferAllocSize;
183
184 Move<VkDescriptorPool> m_descriptorPool;
185 Move<VkDescriptorSetLayout> m_descriptorSetLayout;
186 Move<VkDescriptorSet> m_descriptorSet;
187
188 Move<VkFence> m_fence;
189 VkQueue m_queue;
190
191 de::MovePtr<GraphicsEnvironment> m_graphicsTestEnvironment;
192 };
193
194 class DrawAccessInstance : public VertexAccessInstance
195 {
196 public:
197 DrawAccessInstance(Context &context, Move<VkDevice> device,
198 #ifndef CTS_USES_VULKANSC
199 de::MovePtr<vk::DeviceDriver> deviceDriver,
200 #else
201 de::MovePtr<CustomInstance> customInstance,
202 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
203 #endif // CTS_USES_VULKANSC
204 VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices,
205 uint32_t numInstances);
206
~DrawAccessInstance(void)207 virtual ~DrawAccessInstance(void)
208 {
209 }
210
211 protected:
212 virtual void initVertexIds(uint32_t *indicesPtr, size_t indexCount);
213 virtual uint32_t getIndex(uint32_t vertexNum) const;
214 };
215
216 class DrawIndexedAccessInstance : public VertexAccessInstance
217 {
218 public:
219 DrawIndexedAccessInstance(Context &context, Move<VkDevice> device,
220 #ifndef CTS_USES_VULKANSC
221 de::MovePtr<vk::DeviceDriver> deviceDriver,
222 #else
223 de::MovePtr<CustomInstance> customInstance,
224 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
225 #endif // CTS_USES_VULKANSC
226 VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues,
227 uint32_t numVertices, uint32_t numInstances, const std::vector<uint32_t> &indices);
228
~DrawIndexedAccessInstance(void)229 virtual ~DrawIndexedAccessInstance(void)
230 {
231 }
232
233 protected:
234 virtual void initVertexIds(uint32_t *indicesPtr, size_t indexCount);
235 virtual uint32_t getIndex(uint32_t vertexNum) const;
236
237 const std::vector<uint32_t> m_indices;
238 };
239
240 // VertexAccessTest
241
VertexAccessTest(tcu::TestContext & testContext,const std::string & name,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances)242 VertexAccessTest::VertexAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
243 uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices,
244 uint32_t numInstances)
245
246 : vkt::TestCase(testContext, name)
247 , m_inputFormat(inputFormat)
248 , m_numVertexValues(numVertexValues)
249 , m_numInstanceValues(numInstanceValues)
250 , m_numVertices(numVertices)
251 , m_numInstances(numInstances)
252 {
253 }
254
checkSupport(Context & context) const255 void VertexAccessTest::checkSupport(Context &context) const
256 {
257 if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
258 !context.getDeviceFeatures().robustBufferAccess)
259 TCU_THROW(NotSupportedError,
260 "VK_KHR_portability_subset: robustBufferAccess not supported by this implementation");
261 }
262
initPrograms(SourceCollections & programCollection) const263 void VertexAccessTest::initPrograms(SourceCollections &programCollection) const
264 {
265 std::ostringstream attributeDeclaration;
266 std::ostringstream attributeUse;
267
268 std::ostringstream vertexShaderSource;
269 std::ostringstream fragmentShaderSource;
270
271 std::ostringstream attributeTypeStr;
272 const int numChannels = getNumUsedChannels(mapVkFormat(m_inputFormat).order);
273 const uint32_t numScalarsPerVertex = numChannels * 3; // Use 3 identical attributes
274 uint32_t numValues = 0;
275
276 const bool isR64 = (m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT);
277
278 if (numChannels == 1)
279 {
280 if (isUintFormat(m_inputFormat))
281 attributeTypeStr << "uint";
282 else if (isIntFormat(m_inputFormat))
283 attributeTypeStr << "int";
284 else
285 attributeTypeStr << "float";
286
287 attributeTypeStr << (isR64 ? "64_t" : " ");
288 }
289 else
290 {
291 if (isUintFormat(m_inputFormat))
292 attributeTypeStr << "uvec";
293 else if (isIntFormat(m_inputFormat))
294 attributeTypeStr << "ivec";
295 else
296 attributeTypeStr << "vec";
297
298 attributeTypeStr << numChannels;
299 }
300
301 for (int attrNdx = 0; attrNdx < 3; attrNdx++)
302 {
303 attributeDeclaration << "layout(location = " << attrNdx << ") in " << attributeTypeStr.str() << " attr"
304 << attrNdx << ";\n";
305
306 for (int chanNdx = 0; chanNdx < numChannels; chanNdx++)
307 {
308 attributeUse << "\toutData[(gl_InstanceIndex * " << numScalarsPerVertex * m_numVertices
309 << ") + (vertexNum * " << numScalarsPerVertex << " + " << numValues++ << ")] = attr"
310 << attrNdx;
311
312 if (numChannels == 1)
313 attributeUse << ";\n";
314 else
315 attributeUse << "[" << chanNdx << "];\n";
316 }
317 }
318
319 attributeDeclaration << "layout(location = 3) in int vertexNum;\n";
320
321 attributeUse << "\n";
322
323 std::string outType = "";
324 if (isUintFormat(m_inputFormat))
325 outType = "uint";
326 else if (isIntFormat(m_inputFormat))
327 outType = "int";
328 else
329 outType = "float";
330
331 outType += isR64 ? "64_t" : "";
332
333 std::string extensions = "";
334 std::string version = "#version 310 es\n";
335 if (isR64)
336 {
337 extensions = "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n";
338 version = "#version 440\n";
339 }
340
341 vertexShaderSource << version << "precision highp float;\n"
342 << extensions << attributeDeclaration.str()
343 << "layout(set = 0, binding = 0, std430) buffer outBuffer\n"
344 "{\n"
345 "\t"
346 << outType << " outData[" << (m_numVertices * numValues) * m_numInstances
347 << "];\n"
348 "};\n\n"
349 "void main (void)\n"
350 "{\n"
351 << attributeUse.str()
352 << "\tgl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
353 "}\n";
354
355 programCollection.glslSources.add("vertex") << glu::VertexSource(vertexShaderSource.str());
356
357 fragmentShaderSource << "#version 310 es\n"
358 "precision highp float;\n"
359 "layout(location = 0) out vec4 fragColor;\n"
360 "void main (void)\n"
361 "{\n"
362 "\tfragColor = vec4(1.0);\n"
363 "}\n";
364
365 programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentShaderSource.str());
366 }
367
368 // DrawAccessTest
369
DrawAccessTest(tcu::TestContext & testContext,const std::string & name,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances)370 DrawAccessTest::DrawAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
371 uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices,
372 uint32_t numInstances)
373
374 : VertexAccessTest(testContext, name, inputFormat, numVertexValues, numInstanceValues, numVertices, numInstances)
375 {
376 }
377
createInstance(Context & context) const378 TestInstance *DrawAccessTest::createInstance(Context &context) const
379 {
380 #ifdef CTS_USES_VULKANSC
381 de::MovePtr<CustomInstance> customInstance(new CustomInstance(createCustomInstanceFromContext(context)));
382 #endif // CTS_USES_VULKANSC
383
384 Move<VkDevice> device = createRobustBufferAccessDevice(context
385 #ifdef CTS_USES_VULKANSC
386 ,
387 *customInstance
388 #endif // CTS_USES_VULKANSC
389 );
390 #ifndef CTS_USES_VULKANSC
391 de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(
392 new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion(),
393 context.getTestContext().getCommandLine()));
394 #else
395 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver =
396 de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
397 new DeviceDriverSC(context.getPlatformInterface(), *customInstance, *device,
398 context.getTestContext().getCommandLine(), context.getResourceInterface(),
399 context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(),
400 context.getUsedApiVersion()),
401 vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
402 #endif // CTS_USES_VULKANSC
403
404 return new DrawAccessInstance(context, device,
405 #ifdef CTS_USES_VULKANSC
406 customInstance,
407 #endif // CTS_USES_VULKANSC
408 deviceDriver, m_inputFormat, m_numVertexValues, m_numInstanceValues, m_numVertices,
409 m_numInstances);
410 }
411
412 // DrawIndexedAccessTest
413
414 const uint32_t lastIndexOutOfBounds[] = {
415 0, 1, 2, 3, 4, 100, // Indices of 100 and above are out of bounds
416 };
417 const uint32_t indicesOutOfBounds[] = {
418 0, 100, 2, 101, 3, 102, // Indices of 100 and above are out of bounds
419 };
420 const uint32_t triangleOutOfBounds[] = {
421 100, 101, 102, 3, 4, 5, // Indices of 100 and above are out of bounds
422 };
423
424 const std::vector<uint32_t> DrawIndexedAccessTest::s_indexConfigs[INDEX_CONFIG_COUNT] = {
425 std::vector<uint32_t>(lastIndexOutOfBounds, lastIndexOutOfBounds + DE_LENGTH_OF_ARRAY(lastIndexOutOfBounds)),
426 std::vector<uint32_t>(indicesOutOfBounds, indicesOutOfBounds + DE_LENGTH_OF_ARRAY(indicesOutOfBounds)),
427 std::vector<uint32_t>(triangleOutOfBounds, triangleOutOfBounds + DE_LENGTH_OF_ARRAY(triangleOutOfBounds)),
428 };
429
DrawIndexedAccessTest(tcu::TestContext & testContext,const std::string & name,VkFormat inputFormat,IndexConfig indexConfig)430 DrawIndexedAccessTest::DrawIndexedAccessTest(tcu::TestContext &testContext, const std::string &name,
431 VkFormat inputFormat, IndexConfig indexConfig)
432
433 : VertexAccessTest(testContext, name, inputFormat,
434 getNumUsedChannels(mapVkFormat(inputFormat).order) *
435 (uint32_t)s_indexConfigs[indexConfig].size() * 2, // numVertexValues
436 getNumUsedChannels(mapVkFormat(inputFormat).order), // numInstanceValues
437 (uint32_t)s_indexConfigs[indexConfig].size(), // numVertices
438 1) // numInstances
439 , m_indexConfig(indexConfig)
440 {
441 }
442
createInstance(Context & context) const443 TestInstance *DrawIndexedAccessTest::createInstance(Context &context) const
444 {
445 #ifdef CTS_USES_VULKANSC
446 de::MovePtr<CustomInstance> customInstance(new CustomInstance(createCustomInstanceFromContext(context)));
447 #endif // CTS_USES_VULKANSC
448
449 Move<VkDevice> device = createRobustBufferAccessDevice(context
450 #ifdef CTS_USES_VULKANSC
451 ,
452 *customInstance
453 #endif // CTS_USES_VULKANSC
454 );
455 #ifndef CTS_USES_VULKANSC
456 de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(
457 new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion(),
458 context.getTestContext().getCommandLine()));
459 #else
460 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver =
461 de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
462 new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *device,
463 context.getTestContext().getCommandLine(), context.getResourceInterface(),
464 context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(),
465 context.getUsedApiVersion()),
466 vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
467 #endif // CTS_USES_VULKANSC
468
469 return new DrawIndexedAccessInstance(context, device,
470 #ifdef CTS_USES_VULKANSC
471 customInstance,
472 #endif // CTS_USES_VULKANSC
473 deviceDriver, m_inputFormat, m_numVertexValues, m_numInstanceValues,
474 m_numVertices, m_numInstances, s_indexConfigs[m_indexConfig]);
475 }
476
477 // VertexAccessInstance
478
VertexAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances,const std::vector<uint32_t> & indices)479 VertexAccessInstance::VertexAccessInstance(Context &context, Move<VkDevice> device,
480 #ifndef CTS_USES_VULKANSC
481 de::MovePtr<vk::DeviceDriver> deviceDriver,
482 #else
483 de::MovePtr<CustomInstance> customInstance,
484 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
485 #endif // CTS_USES_VULKANSC
486 VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues,
487 uint32_t numVertices, uint32_t numInstances,
488 const std::vector<uint32_t> &indices)
489
490 : vkt::TestInstance(context)
491 #ifdef CTS_USES_VULKANSC
492 , m_customInstance(customInstance)
493 #endif // CTS_USES_VULKANSC
494 , m_device(device)
495 , m_deviceDriver(deviceDriver)
496 , m_inputFormat(inputFormat)
497 , m_numVertexValues(numVertexValues)
498 , m_numInstanceValues(numInstanceValues)
499 , m_numVertices(numVertices)
500 , m_numInstances(numInstances)
501 {
502 const DeviceInterface &vk = *m_deviceDriver;
503 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
504 const auto &vki = context.getInstanceInterface();
505 const VkPhysicalDevice physicalDevice =
506 chooseDevice(vki, context.getInstance(), context.getTestContext().getCommandLine());
507 SimpleAllocator memAlloc(vk, *m_device, getPhysicalDeviceMemoryProperties(vki, physicalDevice));
508 const uint32_t formatSizeInBytes = tcu::getPixelSize(mapVkFormat(m_inputFormat));
509
510 // Check storage support
511 if (!context.getDeviceFeatures().vertexPipelineStoresAndAtomics)
512 {
513 TCU_THROW(NotSupportedError, "Stores not supported in vertex stage");
514 }
515
516 if (m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT)
517 {
518 const VkFormatProperties formatProperties =
519 getPhysicalDeviceFormatProperties(vki, physicalDevice, m_inputFormat);
520 context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
521
522 if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) !=
523 VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
524 TCU_THROW(NotSupportedError, "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT not supported");
525 }
526
527 const VkVertexInputAttributeDescription attributes[] = {
528 // input rate: vertex
529 {
530 0u, // uint32_t location;
531 0u, // uint32_t binding;
532 m_inputFormat, // VkFormat format;
533 0u, // uint32_t offset;
534 },
535 {
536 1u, // uint32_t location;
537 0u, // uint32_t binding;
538 m_inputFormat, // VkFormat format;
539 formatSizeInBytes, // uint32_t offset;
540 },
541
542 // input rate: instance
543 {
544 2u, // uint32_t location;
545 1u, // uint32_t binding;
546 m_inputFormat, // VkFormat format;
547 0u, // uint32_t offset;
548 },
549
550 // Attribute for vertex number
551 {
552 3u, // uint32_t location;
553 2u, // uint32_t binding;
554 VK_FORMAT_R32_SINT, // VkFormat format;
555 0, // uint32_t offset;
556 },
557 };
558
559 const VkVertexInputBindingDescription bindings[] = {
560 {
561 0u, // uint32_t binding;
562 formatSizeInBytes * 2, // uint32_t stride;
563 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
564 },
565 {
566 1u, // uint32_t binding;
567 formatSizeInBytes, // uint32_t stride;
568 VK_VERTEX_INPUT_RATE_INSTANCE // VkVertexInputRate inputRate;
569 },
570 {
571 2u, // uint32_t binding;
572 sizeof(int32_t), // uint32_t stride;
573 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
574 },
575 };
576
577 m_vertexInputBindings =
578 std::vector<VkVertexInputBindingDescription>(bindings, bindings + DE_LENGTH_OF_ARRAY(bindings));
579 m_vertexInputAttributes =
580 std::vector<VkVertexInputAttributeDescription>(attributes, attributes + DE_LENGTH_OF_ARRAY(attributes));
581
582 // Create vertex buffer for vertex input rate
583 {
584 VkMemoryRequirements bufferMemoryReqs;
585
586 m_vertexRateBufferSize = getBufferSizeInBytes(
587 m_numVertexValues, m_inputFormat); // All formats used in this test suite are 32-bit based.
588
589 const VkBufferCreateInfo vertexRateBufferParams = {
590 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
591 DE_NULL, // const void* pNext;
592 0u, // VkBufferCreateFlags flags;
593 m_vertexRateBufferSize, // VkDeviceSize size;
594 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
595 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
596 1u, // uint32_t queueFamilyIndexCount;
597 &queueFamilyIndex // const uint32_t* pQueueFamilyIndices;
598 };
599
600 m_vertexRateBuffer = createBuffer(vk, *m_device, &vertexRateBufferParams);
601 bufferMemoryReqs = getBufferMemoryRequirements(vk, *m_device, *m_vertexRateBuffer);
602 m_vertexRateBufferAllocSize = bufferMemoryReqs.size;
603 m_vertexRateBufferAlloc = memAlloc.allocate(bufferMemoryReqs, MemoryRequirement::HostVisible);
604
605 VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexRateBuffer, m_vertexRateBufferAlloc->getMemory(),
606 m_vertexRateBufferAlloc->getOffset()));
607 populateBufferWithTestValues(m_vertexRateBufferAlloc->getHostPtr(), (uint32_t)m_vertexRateBufferAllocSize,
608 m_inputFormat);
609 flushMappedMemoryRange(vk, *m_device, m_vertexRateBufferAlloc->getMemory(),
610 m_vertexRateBufferAlloc->getOffset(), VK_WHOLE_SIZE);
611 }
612
613 // Create vertex buffer for instance input rate
614 {
615 VkMemoryRequirements bufferMemoryReqs;
616
617 m_instanceRateBufferSize = getBufferSizeInBytes(
618 m_numInstanceValues, m_inputFormat); // All formats used in this test suite are 32-bit based.
619
620 const VkBufferCreateInfo instanceRateBufferParams = {
621 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
622 DE_NULL, // const void* pNext;
623 0u, // VkBufferCreateFlags flags;
624 m_instanceRateBufferSize, // VkDeviceSize size;
625 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
626 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
627 1u, // uint32_t queueFamilyIndexCount;
628 &queueFamilyIndex // const uint32_t* pQueueFamilyIndices;
629 };
630
631 m_instanceRateBuffer = createBuffer(vk, *m_device, &instanceRateBufferParams);
632 bufferMemoryReqs = getBufferMemoryRequirements(vk, *m_device, *m_instanceRateBuffer);
633 m_instanceRateBufferAllocSize = bufferMemoryReqs.size;
634 m_instanceRateBufferAlloc = memAlloc.allocate(bufferMemoryReqs, MemoryRequirement::HostVisible);
635
636 VK_CHECK(vk.bindBufferMemory(*m_device, *m_instanceRateBuffer, m_instanceRateBufferAlloc->getMemory(),
637 m_instanceRateBufferAlloc->getOffset()));
638 populateBufferWithTestValues(m_instanceRateBufferAlloc->getHostPtr(), (uint32_t)m_instanceRateBufferAllocSize,
639 m_inputFormat);
640 flushMappedMemoryRange(vk, *m_device, m_instanceRateBufferAlloc->getMemory(),
641 m_instanceRateBufferAlloc->getOffset(), VK_WHOLE_SIZE);
642 }
643
644 // Create vertex buffer that stores the vertex number (from 0 to m_numVertices - 1)
645 {
646 m_vertexNumBufferSize = 128 * sizeof(int32_t); // Allocate enough device memory for all indices (0 to 127).
647
648 const VkBufferCreateInfo vertexNumBufferParams = {
649 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
650 DE_NULL, // const void* pNext;
651 0u, // VkBufferCreateFlags flags;
652 m_vertexNumBufferSize, // VkDeviceSize size;
653 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
654 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
655 1u, // uint32_t queueFamilyIndexCount;
656 &queueFamilyIndex // const uint32_t* pQueueFamilyIndices;
657 };
658
659 m_vertexNumBuffer = createBuffer(vk, *m_device, &vertexNumBufferParams);
660 m_vertexNumBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_vertexNumBuffer),
661 MemoryRequirement::HostVisible);
662
663 VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexNumBuffer, m_vertexNumBufferAlloc->getMemory(),
664 m_vertexNumBufferAlloc->getOffset()));
665 }
666
667 // Create index buffer if required
668 if (!indices.empty())
669 {
670 m_indexBufferSize = sizeof(uint32_t) * indices.size();
671
672 const VkBufferCreateInfo indexBufferParams = {
673 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
674 DE_NULL, // const void* pNext;
675 0u, // VkBufferCreateFlags flags;
676 m_indexBufferSize, // VkDeviceSize size;
677 VK_BUFFER_USAGE_INDEX_BUFFER_BIT, // VkBufferUsageFlags usage;
678 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
679 1u, // uint32_t queueFamilyIndexCount;
680 &queueFamilyIndex // const uint32_t* pQueueFamilyIndices;
681 };
682
683 m_indexBuffer = createBuffer(vk, *m_device, &indexBufferParams);
684 m_indexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_indexBuffer),
685 MemoryRequirement::HostVisible);
686
687 VK_CHECK(vk.bindBufferMemory(*m_device, *m_indexBuffer, m_indexBufferAlloc->getMemory(),
688 m_indexBufferAlloc->getOffset()));
689 deMemcpy(m_indexBufferAlloc->getHostPtr(), indices.data(), (size_t)m_indexBufferSize);
690 flushMappedMemoryRange(vk, *m_device, m_indexBufferAlloc->getMemory(), m_indexBufferAlloc->getOffset(),
691 VK_WHOLE_SIZE);
692 }
693
694 // Create result ssbo
695 {
696 const int numChannels = getNumUsedChannels(mapVkFormat(m_inputFormat).order);
697
698 m_outBufferSize = getBufferSizeInBytes(m_numVertices * m_numInstances * numChannels * 3, VK_FORMAT_R32_UINT);
699
700 const VkBufferCreateInfo outBufferParams = {
701 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
702 DE_NULL, // const void* pNext;
703 0u, // VkBufferCreateFlags flags;
704 m_outBufferSize, // VkDeviceSize size;
705 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, // VkBufferUsageFlags usage;
706 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
707 1u, // uint32_t queueFamilyIndexCount;
708 &queueFamilyIndex // const uint32_t* pQueueFamilyIndices;
709 };
710
711 m_outBuffer = createBuffer(vk, *m_device, &outBufferParams);
712 const VkMemoryRequirements requirements = getBufferMemoryRequirements(vk, *m_device, *m_outBuffer);
713 m_outBufferAlloc = memAlloc.allocate(requirements, MemoryRequirement::HostVisible);
714 m_outBufferAllocSize = requirements.size;
715
716 VK_CHECK(
717 vk.bindBufferMemory(*m_device, *m_outBuffer, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset()));
718 deMemset(m_outBufferAlloc->getHostPtr(), 0xFF, (size_t)m_outBufferSize);
719 flushMappedMemoryRange(vk, *m_device, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset(),
720 VK_WHOLE_SIZE);
721 }
722
723 // Create descriptor set data
724 {
725 DescriptorPoolBuilder descriptorPoolBuilder;
726 descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
727 m_descriptorPool =
728 descriptorPoolBuilder.build(vk, *m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
729
730 DescriptorSetLayoutBuilder setLayoutBuilder;
731 setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_VERTEX_BIT);
732 m_descriptorSetLayout = setLayoutBuilder.build(vk, *m_device);
733
734 const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
735 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
736 DE_NULL, // const void* pNext;
737 *m_descriptorPool, // VkDescriptorPool desciptorPool;
738 1u, // uint32_t setLayoutCount;
739 &m_descriptorSetLayout.get() // const VkDescriptorSetLayout* pSetLayouts;
740 };
741
742 m_descriptorSet = allocateDescriptorSet(vk, *m_device, &descriptorSetAllocateInfo);
743
744 const VkDescriptorBufferInfo outBufferDescriptorInfo =
745 makeDescriptorBufferInfo(*m_outBuffer, 0ull, VK_WHOLE_SIZE);
746
747 DescriptorSetUpdateBuilder setUpdateBuilder;
748 setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0),
749 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outBufferDescriptorInfo);
750 setUpdateBuilder.update(vk, *m_device);
751 }
752
753 // Create fence
754 {
755 const VkFenceCreateInfo fenceParams = {
756 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
757 DE_NULL, // const void* pNext;
758 0u // VkFenceCreateFlags flags;
759 };
760
761 m_fence = createFence(vk, *m_device, &fenceParams);
762 }
763
764 // Get queue
765 vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &m_queue);
766
767 // Setup graphics test environment
768 {
769 GraphicsEnvironment::DrawConfig drawConfig;
770
771 drawConfig.vertexBuffers.push_back(*m_vertexRateBuffer);
772 drawConfig.vertexBuffers.push_back(*m_instanceRateBuffer);
773 drawConfig.vertexBuffers.push_back(*m_vertexNumBuffer);
774
775 drawConfig.vertexCount = m_numVertices;
776 drawConfig.instanceCount = m_numInstances;
777 drawConfig.indexBuffer = *m_indexBuffer;
778 drawConfig.indexCount = (uint32_t)(m_indexBufferSize / sizeof(uint32_t));
779
780 m_graphicsTestEnvironment = de::MovePtr<GraphicsEnvironment>(new GraphicsEnvironment(
781 m_context, *m_deviceDriver, *m_device, *m_descriptorSetLayout, *m_descriptorSet,
782 GraphicsEnvironment::VertexBindings(bindings, bindings + DE_LENGTH_OF_ARRAY(bindings)),
783 GraphicsEnvironment::VertexAttributes(attributes, attributes + DE_LENGTH_OF_ARRAY(attributes)),
784 drawConfig));
785 }
786 }
787
~VertexAccessInstance(void)788 VertexAccessInstance::~VertexAccessInstance(void)
789 {
790 }
791
iterate(void)792 tcu::TestStatus VertexAccessInstance::iterate(void)
793 {
794 const DeviceInterface &vk = *m_deviceDriver;
795 const vk::VkCommandBuffer cmdBuffer = m_graphicsTestEnvironment->getCommandBuffer();
796
797 // Initialize vertex ids
798 {
799 uint32_t *bufferPtr = reinterpret_cast<uint32_t *>(m_vertexNumBufferAlloc->getHostPtr());
800 deMemset(bufferPtr, 0, (size_t)m_vertexNumBufferSize);
801
802 initVertexIds(bufferPtr, (size_t)(m_vertexNumBufferSize / sizeof(uint32_t)));
803
804 flushMappedMemoryRange(vk, *m_device, m_vertexNumBufferAlloc->getMemory(), m_vertexNumBufferAlloc->getOffset(),
805 VK_WHOLE_SIZE);
806 }
807
808 // Submit command buffer
809 {
810 const VkSubmitInfo submitInfo = {
811 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
812 DE_NULL, // const void* pNext;
813 0u, // uint32_t waitSemaphoreCount;
814 DE_NULL, // const VkSemaphore* pWaitSemaphores;
815 DE_NULL, // const VkPIpelineStageFlags* pWaitDstStageMask;
816 1u, // uint32_t commandBufferCount;
817 &cmdBuffer, // const VkCommandBuffer* pCommandBuffers;
818 0u, // uint32_t signalSemaphoreCount;
819 DE_NULL // const VkSemaphore* pSignalSemaphores;
820 };
821
822 VK_CHECK(vk.resetFences(*m_device, 1, &m_fence.get()));
823 VK_CHECK(vk.queueSubmit(m_queue, 1, &submitInfo, *m_fence));
824 VK_CHECK(vk.waitForFences(*m_device, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
825 }
826
827 // Prepare result buffer for read
828 {
829 const VkMappedMemoryRange outBufferRange = {
830 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType;
831 DE_NULL, // const void* pNext;
832 m_outBufferAlloc->getMemory(), // VkDeviceMemory mem;
833 0ull, // VkDeviceSize offset;
834 m_outBufferAllocSize, // VkDeviceSize size;
835 };
836
837 VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
838 }
839
840 if (verifyResult())
841 return tcu::TestStatus::pass("All values OK");
842 else
843 return tcu::TestStatus::fail("Invalid value(s) found");
844 }
845
verifyResult(void)846 bool VertexAccessInstance::verifyResult(void)
847 {
848 std::ostringstream logMsg;
849 const DeviceInterface &vk = *m_deviceDriver;
850 tcu::TestLog &log = m_context.getTestContext().getLog();
851 const uint32_t numChannels = getNumUsedChannels(mapVkFormat(m_inputFormat).order);
852 const uint32_t numScalarsPerVertex = numChannels * 3; // Use 3 identical attributes
853 void *outDataPtr = m_outBufferAlloc->getHostPtr();
854 const uint32_t outValueSize = static_cast<uint32_t>(
855 (m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT) ? sizeof(uint64_t) :
856 sizeof(uint32_t));
857 bool allOk = true;
858
859 const VkMappedMemoryRange outBufferRange = {
860 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType;
861 DE_NULL, // const void* pNext;
862 m_outBufferAlloc->getMemory(), // VkDeviceMemory mem;
863 m_outBufferAlloc->getOffset(), // VkDeviceSize offset;
864 m_outBufferAllocSize, // VkDeviceSize size;
865 };
866
867 VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
868
869 for (uint32_t valueNdx = 0; valueNdx < m_outBufferSize / outValueSize; valueNdx++)
870 {
871 uint32_t numInBufferValues;
872 void *inBufferPtr;
873 VkDeviceSize inBufferAllocSize;
874 uint32_t inBufferValueIndex;
875 bool isOutOfBoundsAccess = false;
876 const uint32_t attributeIndex = (valueNdx / numChannels) % 3;
877 uint32_t *ptr32 = (uint32_t *)outDataPtr;
878 uint64_t *ptr64 = (uint64_t *)outDataPtr;
879 const void *outValuePtr =
880 ((m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT) ? (void *)(ptr64 + valueNdx) :
881 (void *)(ptr32 + valueNdx));
882
883 if (attributeIndex == 2)
884 {
885 // Instance rate
886 const uint32_t elementIndex = valueNdx / (numScalarsPerVertex * m_numVertices); // instance id
887
888 numInBufferValues = m_numInstanceValues;
889 inBufferPtr = m_instanceRateBufferAlloc->getHostPtr();
890 inBufferAllocSize = m_instanceRateBufferAllocSize;
891 inBufferValueIndex = (elementIndex * numChannels) + (valueNdx % numScalarsPerVertex) - (2 * numChannels);
892 }
893 else
894 {
895 // Vertex rate
896 const uint32_t vertexNdx = valueNdx / numScalarsPerVertex;
897 const uint32_t instanceNdx = vertexNdx / m_numVertices;
898 const uint32_t elementIndex = valueNdx / numScalarsPerVertex; // vertex id
899
900 numInBufferValues = m_numVertexValues;
901 inBufferPtr = m_vertexRateBufferAlloc->getHostPtr();
902 inBufferAllocSize = m_vertexRateBufferAllocSize;
903 inBufferValueIndex = (getIndex(elementIndex) * (numChannels * 2)) + (valueNdx % numScalarsPerVertex) -
904 instanceNdx * (m_numVertices * numChannels * 2);
905
906 // Binding 0 contains two attributes, so bounds checking for attribute 0 must also consider attribute 1 to determine if the binding is out of bounds.
907 if ((attributeIndex == 0) && (numInBufferValues >= numChannels))
908 numInBufferValues -= numChannels;
909 }
910
911 isOutOfBoundsAccess = (inBufferValueIndex >= numInBufferValues);
912
913 const int32_t distanceToOutOfBounds =
914 (int32_t)outValueSize * ((int32_t)numInBufferValues - (int32_t)inBufferValueIndex);
915
916 if (!isOutOfBoundsAccess && (distanceToOutOfBounds < 16))
917 isOutOfBoundsAccess = (((inBufferValueIndex / numChannels) + 1) * numChannels > numInBufferValues);
918
919 // Log value information
920 {
921 // Vertex separator
922 if (valueNdx && valueNdx % numScalarsPerVertex == 0)
923 logMsg << "\n";
924
925 logMsg << "\n" << valueNdx << ": Value ";
926
927 // Result index and value
928 if (m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
929 logValue(logMsg, outValuePtr, VK_FORMAT_R32_SFLOAT, 4);
930 else
931 logValue(logMsg, outValuePtr, m_inputFormat, 4);
932
933 // Attribute name
934 logMsg << "\tfrom attr" << attributeIndex;
935 if (numChannels > 1)
936 logMsg << "[" << valueNdx % numChannels << "]";
937
938 // Input rate
939 if (attributeIndex == 2)
940 logMsg << "\tinstance rate";
941 else
942 logMsg << "\tvertex rate";
943 }
944
945 if (isOutOfBoundsAccess)
946 {
947 const bool isValidValue =
948 isValueWithinVertexBufferOrZero(inBufferPtr, inBufferAllocSize, outValuePtr, inBufferValueIndex);
949
950 logMsg << "\t(out of bounds)";
951
952 if (!isValidValue)
953 {
954 // Check if we are satisfying the [0, 0, 0, x] pattern, where x may be either 0 or 1,
955 // or the maximum representable positive integer value (if the format is integer-based).
956
957 const bool canMatchVec4Pattern =
958 ((valueNdx % numChannels == 3) || m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32);
959 bool matchesVec4Pattern = false;
960
961 if (canMatchVec4Pattern)
962 {
963 if (m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
964 matchesVec4Pattern = verifyOutOfBoundsVec4(outValuePtr, m_inputFormat);
965 else
966 matchesVec4Pattern = verifyOutOfBoundsVec4(((uint32_t *)outValuePtr) - 3, m_inputFormat);
967 }
968
969 if (!canMatchVec4Pattern || !matchesVec4Pattern)
970 {
971 logMsg << ", Failed: expected a value within the buffer range or 0";
972
973 if (canMatchVec4Pattern)
974 logMsg << ", or the [0, 0, 0, x] pattern";
975
976 allOk = false;
977 }
978 }
979 }
980 else if (!isExpectedValueFromVertexBuffer(inBufferPtr, inBufferValueIndex, m_inputFormat, outValuePtr))
981 {
982 logMsg << ", Failed: unexpected value";
983 allOk = false;
984 }
985 }
986 log << tcu::TestLog::Message << logMsg.str() << tcu::TestLog::EndMessage;
987
988 return allOk;
989 }
990
isValueWithinVertexBufferOrZero(void * vertexBuffer,VkDeviceSize vertexBufferSize,const void * value,uint32_t valueIndex)991 bool VertexAccessInstance::isValueWithinVertexBufferOrZero(void *vertexBuffer, VkDeviceSize vertexBufferSize,
992 const void *value, uint32_t valueIndex)
993 {
994 if (m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
995 {
996 const float normValue = *reinterpret_cast<const float *>(value);
997 const uint32_t scalarIndex = valueIndex % 4;
998 const bool isAlpha = (scalarIndex == 3);
999 uint32_t encodedValue;
1000
1001 if (isAlpha)
1002 encodedValue = deMin32(uint32_t(deFloatRound(normValue * 0x3u)), 0x3u);
1003 else
1004 encodedValue = deMin32(uint32_t(deFloatRound(normValue * 0x3FFu)), 0x3FFu);
1005
1006 if (encodedValue == 0)
1007 return true;
1008
1009 for (uint32_t i = 0; i < vertexBufferSize / 4; i++)
1010 {
1011 const uint32_t packedValue = reinterpret_cast<uint32_t *>(vertexBuffer)[i];
1012 uint32_t unpackedValue;
1013
1014 if (scalarIndex < 3)
1015 unpackedValue = (packedValue >> (10 * scalarIndex)) & 0x3FFu;
1016 else
1017 unpackedValue = (packedValue >> 30) & 0x3u;
1018
1019 if (unpackedValue == encodedValue)
1020 return true;
1021 }
1022
1023 return false;
1024 }
1025 else
1026 {
1027 return isValueWithinBufferOrZero(vertexBuffer, vertexBufferSize, value, sizeof(uint32_t));
1028 }
1029 }
1030
isExpectedValueFromVertexBuffer(const void * vertexBuffer,uint32_t vertexIndex,VkFormat vertexFormat,const void * value)1031 bool VertexAccessInstance::isExpectedValueFromVertexBuffer(const void *vertexBuffer, uint32_t vertexIndex,
1032 VkFormat vertexFormat, const void *value)
1033 {
1034 if (isUintFormat(vertexFormat))
1035 {
1036 if (vertexFormat == VK_FORMAT_R64_UINT || vertexFormat == VK_FORMAT_R64_SINT)
1037 {
1038 const uint64_t *bufferPtr = reinterpret_cast<const uint64_t *>(vertexBuffer);
1039 return bufferPtr[vertexIndex] == *reinterpret_cast<const uint64_t *>(value);
1040 }
1041 else
1042 {
1043 const uint32_t *bufferPtr = reinterpret_cast<const uint32_t *>(vertexBuffer);
1044 return bufferPtr[vertexIndex] == *reinterpret_cast<const uint32_t *>(value);
1045 }
1046 }
1047 else if (isIntFormat(vertexFormat))
1048 {
1049 if (vertexFormat == VK_FORMAT_R64_UINT || vertexFormat == VK_FORMAT_R64_SINT)
1050 {
1051 const int64_t *bufferPtr = reinterpret_cast<const int64_t *>(vertexBuffer);
1052 return bufferPtr[vertexIndex] == *reinterpret_cast<const int64_t *>(value);
1053 }
1054 else
1055 {
1056 const int32_t *bufferPtr = reinterpret_cast<const int32_t *>(vertexBuffer);
1057 return bufferPtr[vertexIndex] == *reinterpret_cast<const int32_t *>(value);
1058 }
1059 }
1060 else if (isFloatFormat(vertexFormat))
1061 {
1062 const float *bufferPtr = reinterpret_cast<const float *>(vertexBuffer);
1063
1064 return areEqual(bufferPtr[vertexIndex], *reinterpret_cast<const float *>(value));
1065 }
1066 else if (vertexFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1067 {
1068 const uint32_t *bufferPtr = reinterpret_cast<const uint32_t *>(vertexBuffer);
1069 const uint32_t packedValue = bufferPtr[vertexIndex / 4];
1070 const uint32_t scalarIndex = vertexIndex % 4;
1071 float normValue;
1072
1073 if (scalarIndex < 3)
1074 normValue = float((packedValue >> (10 * scalarIndex)) & 0x3FFu) / 0x3FFu;
1075 else
1076 normValue = float(packedValue >> 30) / 0x3u;
1077
1078 return areEqual(normValue, *reinterpret_cast<const float *>(value));
1079 }
1080
1081 DE_ASSERT(false);
1082 return false;
1083 }
1084
getBufferSizeInBytes(uint32_t numScalars,VkFormat format)1085 VkDeviceSize VertexAccessInstance::getBufferSizeInBytes(uint32_t numScalars, VkFormat format)
1086 {
1087 if (isUintFormat(format) || isIntFormat(format) || isFloatFormat(format))
1088 {
1089 return numScalars * ((format == VK_FORMAT_R64_UINT || format == VK_FORMAT_R64_SINT) ? 8 : 4);
1090 }
1091 else if (format == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1092 {
1093 DE_ASSERT(numScalars % 4 == 0);
1094 return numScalars;
1095 }
1096
1097 DE_ASSERT(false);
1098 return 0;
1099 }
1100
1101 // DrawAccessInstance
1102
DrawAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances)1103 DrawAccessInstance::DrawAccessInstance(Context &context, Move<VkDevice> device,
1104 #ifndef CTS_USES_VULKANSC
1105 de::MovePtr<vk::DeviceDriver> deviceDriver,
1106 #else
1107 de::MovePtr<CustomInstance> customInstance,
1108 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
1109 #endif // CTS_USES_VULKANSC
1110 VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues,
1111 uint32_t numVertices, uint32_t numInstances)
1112 : VertexAccessInstance(context, device,
1113 #ifdef CTS_USES_VULKANSC
1114 customInstance,
1115 #endif // CTS_USES_VULKANSC
1116 deviceDriver, inputFormat, numVertexValues, numInstanceValues, numVertices, numInstances,
1117 std::vector<uint32_t>()) // No index buffer
1118 {
1119 }
1120
initVertexIds(uint32_t * indicesPtr,size_t indexCount)1121 void DrawAccessInstance::initVertexIds(uint32_t *indicesPtr, size_t indexCount)
1122 {
1123 for (uint32_t i = 0; i < indexCount; i++)
1124 indicesPtr[i] = i;
1125 }
1126
getIndex(uint32_t vertexNum) const1127 uint32_t DrawAccessInstance::getIndex(uint32_t vertexNum) const
1128 {
1129 return vertexNum;
1130 }
1131
1132 // DrawIndexedAccessInstance
1133
DrawIndexedAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances,const std::vector<uint32_t> & indices)1134 DrawIndexedAccessInstance::DrawIndexedAccessInstance(Context &context, Move<VkDevice> device,
1135 #ifndef CTS_USES_VULKANSC
1136 de::MovePtr<vk::DeviceDriver> deviceDriver,
1137 #else
1138 de::MovePtr<CustomInstance> customInstance,
1139 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>
1140 deviceDriver,
1141 #endif // CTS_USES_VULKANSC
1142 VkFormat inputFormat, uint32_t numVertexValues,
1143 uint32_t numInstanceValues, uint32_t numVertices,
1144 uint32_t numInstances, const std::vector<uint32_t> &indices)
1145 : VertexAccessInstance(context, device,
1146 #ifdef CTS_USES_VULKANSC
1147 customInstance,
1148 #endif // CTS_USES_VULKANSC
1149 deviceDriver, inputFormat, numVertexValues, numInstanceValues, numVertices, numInstances,
1150 indices)
1151 , m_indices(indices)
1152 {
1153 }
1154
initVertexIds(uint32_t * indicesPtr,size_t indexCount)1155 void DrawIndexedAccessInstance::initVertexIds(uint32_t *indicesPtr, size_t indexCount)
1156 {
1157 DE_UNREF(indexCount);
1158
1159 for (uint32_t i = 0; i < m_indices.size(); i++)
1160 {
1161 DE_ASSERT(m_indices[i] < indexCount);
1162
1163 indicesPtr[m_indices[i]] = i;
1164 }
1165 }
1166
getIndex(uint32_t vertexNum) const1167 uint32_t DrawIndexedAccessInstance::getIndex(uint32_t vertexNum) const
1168 {
1169 DE_ASSERT(vertexNum < (uint32_t)m_indices.size());
1170
1171 return m_indices[vertexNum];
1172 }
1173
1174 // Test node creation functions
1175
createDrawTests(tcu::TestContext & testCtx,VkFormat format)1176 static tcu::TestCaseGroup *createDrawTests(tcu::TestContext &testCtx, VkFormat format)
1177 {
1178 struct TestConfig
1179 {
1180 std::string name;
1181 VkFormat inputFormat;
1182 uint32_t numVertexValues;
1183 uint32_t numInstanceValues;
1184 uint32_t numVertices;
1185 uint32_t numInstances;
1186 };
1187
1188 const uint32_t numChannels = getNumUsedChannels(mapVkFormat(format).order);
1189
1190 const TestConfig testConfigs[] = {
1191 // name format numVertexValues numInstanceValues numVertices numInstances
1192 // Create data for 6 vertices, draw 9 vertices
1193 {"vertex_out_of_bounds", format, numChannels * 2 * 6, numChannels, 9, 1},
1194 // Create data for half a vertex, draw 3 vertices
1195 {"vertex_incomplete", format, numChannels, numChannels, 3, 1},
1196 // Create data for 1 instance, draw 3 instances
1197 {"instance_out_of_bounds", format, numChannels * 2 * 9, numChannels, 3, 3},
1198 };
1199
1200 de::MovePtr<tcu::TestCaseGroup> drawTests(new tcu::TestCaseGroup(testCtx, "draw"));
1201
1202 for (int i = 0; i < DE_LENGTH_OF_ARRAY(testConfigs); i++)
1203 {
1204 const TestConfig &config = testConfigs[i];
1205
1206 drawTests->addChild(new DrawAccessTest(testCtx, config.name, config.inputFormat, config.numVertexValues,
1207 config.numInstanceValues, config.numVertices, config.numInstances));
1208 }
1209
1210 return drawTests.release();
1211 }
1212
createDrawIndexedTests(tcu::TestContext & testCtx,VkFormat format)1213 static tcu::TestCaseGroup *createDrawIndexedTests(tcu::TestContext &testCtx, VkFormat format)
1214 {
1215 struct TestConfig
1216 {
1217 std::string name;
1218 VkFormat inputFormat;
1219 DrawIndexedAccessTest::IndexConfig indexConfig;
1220 };
1221
1222 const TestConfig testConfigs[] = {
1223 // name format indexConfig
1224 // Only last index is out of bounds
1225 {"last_index_out_of_bounds", format, DrawIndexedAccessTest::INDEX_CONFIG_LAST_INDEX_OUT_OF_BOUNDS},
1226 // Random indices out of bounds
1227 {"indices_out_of_bounds", format, DrawIndexedAccessTest::INDEX_CONFIG_INDICES_OUT_OF_BOUNDS},
1228 // First triangle is out of bounds
1229 {"triangle_out_of_bounds", format, DrawIndexedAccessTest::INDEX_CONFIG_TRIANGLE_OUT_OF_BOUNDS},
1230 };
1231
1232 de::MovePtr<tcu::TestCaseGroup> drawTests(new tcu::TestCaseGroup(testCtx, "draw_indexed"));
1233
1234 for (int i = 0; i < DE_LENGTH_OF_ARRAY(testConfigs); i++)
1235 {
1236 const TestConfig &config = testConfigs[i];
1237
1238 drawTests->addChild(new DrawIndexedAccessTest(testCtx, config.name, config.inputFormat, config.indexConfig));
1239 }
1240
1241 return drawTests.release();
1242 }
1243
addVertexFormatTests(tcu::TestContext & testCtx,tcu::TestCaseGroup * parentGroup)1244 static void addVertexFormatTests(tcu::TestContext &testCtx, tcu::TestCaseGroup *parentGroup)
1245 {
1246 const VkFormat vertexFormats[] = {VK_FORMAT_R32_UINT,
1247 VK_FORMAT_R32_SINT,
1248 VK_FORMAT_R32_SFLOAT,
1249 VK_FORMAT_R32G32_UINT,
1250 VK_FORMAT_R32G32_SINT,
1251 VK_FORMAT_R32G32_SFLOAT,
1252 VK_FORMAT_R32G32B32_UINT,
1253 VK_FORMAT_R32G32B32_SINT,
1254 VK_FORMAT_R32G32B32_SFLOAT,
1255 VK_FORMAT_R32G32B32A32_UINT,
1256 VK_FORMAT_R32G32B32A32_SINT,
1257 VK_FORMAT_R32G32B32A32_SFLOAT,
1258 VK_FORMAT_R64_UINT,
1259 VK_FORMAT_R64_SINT,
1260
1261 VK_FORMAT_A2B10G10R10_UNORM_PACK32};
1262
1263 for (int i = 0; i < DE_LENGTH_OF_ARRAY(vertexFormats); i++)
1264 {
1265 const std::string formatName = getFormatName(vertexFormats[i]);
1266 de::MovePtr<tcu::TestCaseGroup> formatGroup(
1267 new tcu::TestCaseGroup(testCtx, de::toLower(formatName.substr(10)).c_str()));
1268
1269 formatGroup->addChild(createDrawTests(testCtx, vertexFormats[i]));
1270 formatGroup->addChild(createDrawIndexedTests(testCtx, vertexFormats[i]));
1271
1272 parentGroup->addChild(formatGroup.release());
1273 }
1274 }
1275
createVertexAccessTests(tcu::TestContext & testCtx)1276 tcu::TestCaseGroup *createVertexAccessTests(tcu::TestContext &testCtx)
1277 {
1278 de::MovePtr<tcu::TestCaseGroup> vertexAccessTests(new tcu::TestCaseGroup(testCtx, "vertex_access"));
1279
1280 addVertexFormatTests(testCtx, vertexAccessTests.get());
1281
1282 return vertexAccessTests.release();
1283 }
1284
1285 } // namespace robustness
1286 } // namespace vkt
1287